From 6c70c403be951d8da2d9ea949c63dabd320a3e64 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:04:11 -0600 Subject: [PATCH 01/29] Implement FillJournal console command --- apps/openmw/mwscript/dialogueextensions.cpp | 59 +++++++++++++++++---- apps/openmw/mwscript/docs/vmformat.txt | 3 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 6511fbdb01..643efb3d07 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,6 +22,20 @@ namespace MWScript { + static void addJournalEntry(ESM::RefId quest, int index, MWWorld::Ptr ptr) + { + // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( + try + { + MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); + } + catch (...) + { + if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + } + } + namespace Dialogue { template @@ -40,16 +54,7 @@ namespace MWScript Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( - try - { - MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); - } - catch (...) - { - if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) - MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); - } + addJournalEntry(quest, index, ptr); } }; @@ -82,6 +87,39 @@ namespace MWScript } }; + class OpFillJournal : public Interpreter::Opcode0 + { + public: + void execute(Interpreter::Runtime& runtime) override + { + const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + for (auto it = dialogues.begin(); it != dialogues.end(); ++it) + { + const ESM::Dialogue::Type type = it->mType; + if (type == ESM::Dialogue::Type::Journal) + { + ESM::RefId quest = ESM::RefId::stringRefId(it->mStringId); + const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); + for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + { + addJournalEntry(quest, info->mData.mJournalIndex, ptr); + } + } + else if (type == ESM::Dialogue::Type::Topic) + { + ESM::RefId topic = ESM::RefId::stringRefId(it->mStringId); + const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); + for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + { + MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); + } + } + } + } + }; + class OpAddTopic : public Interpreter::Opcode0 { public: @@ -288,6 +326,7 @@ namespace MWScript interpreter.installSegment5>(Compiler::Dialogue::opcodeJournalExplicit); interpreter.installSegment5(Compiler::Dialogue::opcodeSetJournalIndex); interpreter.installSegment5(Compiler::Dialogue::opcodeGetJournalIndex); + interpreter.installSegment5(Compiler::Dialogue::opcodeFillJournal); interpreter.installSegment5(Compiler::Dialogue::opcodeAddTopic); interpreter.installSegment3(Compiler::Dialogue::opcodeChoice); interpreter.installSegment5>(Compiler::Dialogue::opcodeForceGreeting); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d34c39c9df..56eb1c2351 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -485,5 +485,6 @@ op 0x2000322: GetPCVisionBonus op 0x2000323: SetPCVisionBonus op 0x2000324: ModPCVisionBonus op 0x2000325: TestModels, T3D +op 0x2000326: FillJournal -opcodes 0x2000326-0x3ffffff unused +opcodes 0x2000327-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 6f57ee7673..103fb41641 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -163,6 +163,7 @@ namespace Compiler extensions.registerInstruction("journal", "cl", opcodeJournal, opcodeJournalExplicit); extensions.registerInstruction("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction("getjournalindex", 'l', "c", opcodeGetJournalIndex); + extensions.registerInstruction("filljournal", "", opcodeFillJournal); extensions.registerInstruction("addtopic", "S", opcodeAddTopic); extensions.registerInstruction( "choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 2ec31c7588..55f431f049 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -155,6 +155,7 @@ namespace Compiler const int opcodeJournalExplicit = 0x200030b; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; + const int opcodeFillJournal = 0x2000326; const int opcodeAddTopic = 0x200013a; const int opcodeChoice = 0x2000a; const int opcodeForceGreeting = 0x200014f; From 2e1f3d5d2c0da9e7a680ce6bd79fcb00d49a6dbe Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:17:32 -0600 Subject: [PATCH 02/29] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 643efb3d07..93241c3ff4 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -92,7 +92,8 @@ namespace MWScript public: void execute(Interpreter::Runtime& runtime) override { - const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); + const MWWorld::Store& dialogues + = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); for (auto it = dialogues.begin(); it != dialogues.end(); ++it) From 34194f9c0841fda8e06615b1bfbea2a9a7aac7ce Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:28:05 -0600 Subject: [PATCH 03/29] Add topics as known topics in addition to journal topics --- apps/openmw/mwscript/dialogueextensions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 93241c3ff4..17145e9b32 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -116,6 +116,7 @@ namespace MWScript { MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); } + MWBase::Environment::get().getDialogueManager()->addTopic(topic); } } } From 4b9852026637ecaf39ac83fceb6d5341d1edca39 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:32:05 -0600 Subject: [PATCH 04/29] Revert shared addJournalEntry --- apps/openmw/mwscript/dialogueextensions.cpp | 27 +++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 17145e9b32..869b626728 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,20 +22,6 @@ namespace MWScript { - static void addJournalEntry(ESM::RefId quest, int index, MWWorld::Ptr ptr) - { - // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( - try - { - MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); - } - catch (...) - { - if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) - MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); - } - } - namespace Dialogue { template @@ -54,7 +40,16 @@ namespace MWScript Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - addJournalEntry(quest, index, ptr); + // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( + try + { + MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); + } + catch (...) + { + if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + } } }; @@ -105,7 +100,7 @@ namespace MWScript const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) { - addJournalEntry(quest, info->mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry(quest, info->mData.mJournalIndex, ptr); } } else if (type == ESM::Dialogue::Type::Topic) From 83903455f9f22257cbc649ceda6bbd31b96a1c38 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:51:53 -0600 Subject: [PATCH 05/29] Address review comments --- apps/openmw/mwscript/dialogueextensions.cpp | 22 +++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 869b626728..ab48807c36 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -91,27 +91,23 @@ namespace MWScript = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - for (auto it = dialogues.begin(); it != dialogues.end(); ++it) + for (const auto& dialogue : dialogues) { - const ESM::Dialogue::Type type = it->mType; - if (type == ESM::Dialogue::Type::Journal) + if (dialogue.mType == ESM::Dialogue::Type::Journal) { - ESM::RefId quest = ESM::RefId::stringRefId(it->mStringId); - const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); - for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry(quest, info->mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry(dialogue.mId, + journalInfo.mData.mJournalIndex, ptr); } } - else if (type == ESM::Dialogue::Type::Topic) + else if (dialogue.mType == ESM::Dialogue::Type::Topic) { - ESM::RefId topic = ESM::RefId::stringRefId(it->mStringId); - const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); - for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); + MWBase::Environment::get().getJournal()->addTopic(dialogue.mId, topicInfo.mId, ptr); } - MWBase::Environment::get().getDialogueManager()->addTopic(topic); + MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); } } } From 565b199380c8176ebbc2910f0ee57dbff60d60ed Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:54:27 -0600 Subject: [PATCH 06/29] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ab48807c36..6b3787f948 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -97,8 +97,8 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry(dialogue.mId, - journalInfo.mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry( + dialogue.mId, journalInfo.mData.mJournalIndex, ptr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From 30140d95488b13b8dfe6dbbb778fa32343a979ab Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:34:00 -0600 Subject: [PATCH 07/29] Get the journal only once --- apps/openmw/mwscript/dialogueextensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 6b3787f948..1c7de21d57 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -90,6 +90,7 @@ namespace MWScript const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Journal* journal = MWBase::Environment::get().getJournal(); for (const auto& dialogue : dialogues) { @@ -97,7 +98,7 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry( + journal->addEntry( dialogue.mId, journalInfo.mData.mJournalIndex, ptr); } } @@ -105,7 +106,7 @@ namespace MWScript { for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addTopic(dialogue.mId, topicInfo.mId, ptr); + journal->addTopic(dialogue.mId, topicInfo.mId, ptr); } MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); } From 73a3033e0ffd6a93386890690c1692550159c11a Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:42:27 -0600 Subject: [PATCH 08/29] Get the dialogue manager once --- apps/openmw/mwscript/dialogueextensions.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 1c7de21d57..edf6f4b6df 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -89,8 +89,9 @@ namespace MWScript { const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWBase::Journal* journal = MWBase::Environment::get().getJournal(); + MWBase::DialogueManager* dialogueManager = MWBase::Environment::get().getDialogueManager(); for (const auto& dialogue : dialogues) { @@ -99,16 +100,16 @@ namespace MWScript for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { journal->addEntry( - dialogue.mId, journalInfo.mData.mJournalIndex, ptr); + dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) { for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addTopic(dialogue.mId, topicInfo.mId, ptr); + journal->addTopic(dialogue.mId, topicInfo.mId, playerPtr); } - MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); + dialogueManager->addTopic(dialogue.mId); } } } From 0e1ed078e9380fc1b4ce3213de2bd8bee312daac Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:56:43 -0600 Subject: [PATCH 09/29] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index edf6f4b6df..23d8049a5d 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -99,8 +99,7 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addEntry( - dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); + journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From d207c2251ffe4693f73e275c8df95bc7127c0010 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Jul 2025 11:38:15 -0600 Subject: [PATCH 10/29] Fix unneeded runtime errors --- apps/openmw/mwscript/interpretercontext.cpp | 26 ++++++-- components/interpreter/defines.cpp | 70 +++++++++++---------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 15c9100b98..9aeccfc886 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -300,7 +301,15 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const ESM::NPC* npc = getReferenceImp().get()->mBase; + const MWWorld::Ptr& ptr = getReferenceImp(); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCFaction(): NPC is not in a faction"; + return "%"; + } + + const ESM::NPC* npc = ptr.get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -310,7 +319,10 @@ namespace MWScript const MWWorld::Ptr& ptr = getReferenceImp(); const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); if (faction.empty()) - throw std::runtime_error("getNPCRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getNPCRank(): NPC is not in a faction"; + return "%"; + } int rank = ptr.getClass().getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) @@ -349,7 +361,10 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - throw std::runtime_error("getPCRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getPCRank(): NPC is not in a faction"; + return "%"; + } const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); @@ -378,7 +393,10 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getPCNextRank(): NPC is not in a faction"; + return "%"; + } const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index e7a8e35328..6d51a72cca 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -26,40 +26,40 @@ namespace std::vector globals; const std::initializer_list> sActionBindings{ - { "actionslideright", "#{sRight}" }, - { "actionreadymagic", "#{sReady_Magic}" }, - { "actionprevweapon", "#{sPrevWeapon}" }, - { "actionnextweapon", "#{sNextWeapon}" }, - { "actiontogglerun", "#{sAuto_Run}" }, - { "actionslideleft", "#{sLeft}" }, - { "actionreadyitem", "#{sReady_Weapon}" }, - { "actionprevspell", "#{sPrevSpell}" }, - { "actionnextspell", "#{sNextSpell}" }, - { "actionrestmenu", "#{sRestKey}" }, - { "actionmenumode", "#{sInventory}" }, - { "actionactivate", "#{sActivate}" }, - { "actionjournal", "#{sJournal}" }, - { "actionforward", "#{sForward}" }, - { "actioncrouch", "#{sCrouch_Sneak}" }, - { "actionjump", "#{sJump}" }, - { "actionback", "#{sBack}" }, - { "actionuse", "#{sUse}" }, - { "actionrun", "#{sRun}" }, + { "ActionSlideRight", "#{sRight}" }, + { "ActionReadyMagic", "#{sReady_Magic}" }, + { "ActionPrevWeapon", "#{sPrevWeapon}" }, + { "ActionNextWeapon", "#{sNextWeapon}" }, + { "ActionToggleRun", "#{sAuto_Run}" }, + { "ActionSlideLeft", "#{sLeft}" }, + { "ActionReadyItem", "#{sReady_Weapon}" }, + { "ActionPrevSpell", "#{sPrevSpell}" }, + { "ActionNextSpell", "#{sNextSpell}" }, + { "ActionRestMenu", "#{sRestKey}" }, + { "ActionMenuMode", "#{sInventory}" }, + { "ActionActivate", "#{sActivate}" }, + { "ActionJournal", "#{sJournal}" }, + { "ActionForward", "#{sForward}" }, + { "ActionCrouch", "#{sCrouch_Sneak}" }, + { "ActionJump", "#{sJump}" }, + { "ActionBack", "#{sBack}" }, + { "ActionUse", "#{sUse}" }, + { "ActionRun", "#{sRun}" }, }; using ContextMethod = std::string_view (Interpreter::Context::*)() const; const std::initializer_list>> sContextMethods{ - { "nextpcrank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "pcnextrank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "faction", { &Interpreter::Context::getNPCFaction, nullptr } }, - { "pcclass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, - { "pcname", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, - { "pcrace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, - { "pcrank", { &Interpreter::Context::getPCRank, nullptr } }, - { "class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, - { "cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, - { "race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, - { "rank", { &Interpreter::Context::getNPCRank, nullptr } }, - { "name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, + { "NextPCRank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "PCNextRank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "Faction", { &Interpreter::Context::getNPCFaction, nullptr } }, + { "PCClass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, + { "PCName", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, + { "PCRace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, + { "PCRank", { &Interpreter::Context::getPCRank, nullptr } }, + { "Class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, + { "Cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, + { "Race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, + { "Rank", { &Interpreter::Context::getNPCRank, nullptr } }, + { "Name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, }; bool longerStr(std::string_view a, std::string_view b) @@ -78,7 +78,7 @@ namespace return true; } } - if (check(temp, "pccrimelevel", i, start)) + if (check(temp, "PCCrimeLevel", i, start)) { retval << context.getPCBounty(); return true; @@ -89,7 +89,13 @@ namespace if (check(temp, name, i, start)) { if (method) // Not all variables are available outside of dialogue + { retval << (context.*method)(); + + // Re-add the token if replacement failed without an error + if ((context.*method)() == "%") + retval << name; + } return true; } } From 555721141d8d1a6b1587b38400addbb2fc7e6d43 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Jul 2025 15:22:52 -0600 Subject: [PATCH 11/29] Skip quest names (vanilla improvement) --- apps/openmw/mwscript/dialogueextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 23d8049a5d..6c219a52a3 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -99,7 +99,8 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); + if (journalInfo.mQuestStatus != ESM::DialInfo::QS_Name) + journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From 6a9b2d330210ccdeb6f98a69ad86a8a0928fb1f4 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sun, 6 Jul 2025 17:27:40 -0500 Subject: [PATCH 12/29] [CI] Brew cleanup/simplify --- .gitlab-ci.yml | 6 ++++++ CI/before_install.macos.sh | 4 ---- CI/macos/before_install.arm64.sh | 9 +-------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc638729c4..f1c96b1776 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -546,6 +546,9 @@ macOS14_Xcode15_amd64: CCACHE_SIZE: 3G DMG_IDENTIFIER: amd64 MACOS_AMD64: true + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_EMOJI: true + HOMEBREW_NO_INSTALL_CLEANUP: true macOS14_Xcode15_arm64: extends: .MacOS @@ -557,6 +560,9 @@ macOS14_Xcode15_arm64: variables: DMG_IDENTIFIER: arm64 CCACHE_SIZE: 3G + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_EMOJI: true + HOMEBREW_NO_INSTALL_CLEANUP: true .Compress_And_Upload_Symbols_Base: extends: .Ubuntu_Image diff --git a/CI/before_install.macos.sh b/CI/before_install.macos.sh index f466dd06a7..60d2d3a38c 100755 --- a/CI/before_install.macos.sh +++ b/CI/before_install.macos.sh @@ -1,9 +1,5 @@ #!/bin/sh -ex -export HOMEBREW_NO_EMOJI=1 -export HOMEBREW_NO_INSTALL_CLEANUP=1 -export HOMEBREW_AUTOREMOVE=1 - if [[ "${MACOS_AMD64}" ]]; then ./CI/macos/before_install.amd64.sh else diff --git a/CI/macos/before_install.arm64.sh b/CI/macos/before_install.arm64.sh index 84120dfba2..d53d847b1c 100755 --- a/CI/macos/before_install.arm64.sh +++ b/CI/macos/before_install.arm64.sh @@ -3,14 +3,7 @@ brew tap --repair brew update --quiet -brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd - -command -v ccache >/dev/null 2>&1 || brew install ccache -command -v cmake >/dev/null 2>&1 || brew install cmake -command -v qmake >/dev/null 2>&1 || brew install qt@6 - -# Install deps -brew install openal-soft icu4c yaml-cpp sqlite +brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd ccache cmake qt@6 openal-soft icu4c yaml-cpp sqlite curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz -o ~/openmw-deps.tar.xz tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null From 67795543a296a415e47a516c883a8f5e3a410f21 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 6 Jul 2025 20:51:53 -0600 Subject: [PATCH 13/29] Revert "Fix unneeded runtime errors" This reverts commit d207c2251ffe4693f73e275c8df95bc7127c0010. --- apps/openmw/mwscript/interpretercontext.cpp | 26 ++------ components/interpreter/defines.cpp | 70 ++++++++++----------- 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 9aeccfc886..15c9100b98 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "../mwworld/esmstore.hpp" @@ -301,15 +300,7 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const MWWorld::Ptr& ptr = getReferenceImp(); - const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); - if (factionId.empty()) - { - Log(Debug::Warning) << "getNPCFaction(): NPC is not in a faction"; - return "%"; - } - - const ESM::NPC* npc = ptr.get()->mBase; + const ESM::NPC* npc = getReferenceImp().get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -319,10 +310,7 @@ namespace MWScript const MWWorld::Ptr& ptr = getReferenceImp(); const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); if (faction.empty()) - { - Log(Debug::Warning) << "getNPCRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getNPCRank(): NPC is not in a faction"); int rank = ptr.getClass().getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) @@ -361,10 +349,7 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - { - Log(Debug::Warning) << "getPCRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getPCRank(): NPC is not in a faction"); const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); @@ -393,10 +378,7 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - { - Log(Debug::Warning) << "getPCNextRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 6d51a72cca..e7a8e35328 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -26,40 +26,40 @@ namespace std::vector globals; const std::initializer_list> sActionBindings{ - { "ActionSlideRight", "#{sRight}" }, - { "ActionReadyMagic", "#{sReady_Magic}" }, - { "ActionPrevWeapon", "#{sPrevWeapon}" }, - { "ActionNextWeapon", "#{sNextWeapon}" }, - { "ActionToggleRun", "#{sAuto_Run}" }, - { "ActionSlideLeft", "#{sLeft}" }, - { "ActionReadyItem", "#{sReady_Weapon}" }, - { "ActionPrevSpell", "#{sPrevSpell}" }, - { "ActionNextSpell", "#{sNextSpell}" }, - { "ActionRestMenu", "#{sRestKey}" }, - { "ActionMenuMode", "#{sInventory}" }, - { "ActionActivate", "#{sActivate}" }, - { "ActionJournal", "#{sJournal}" }, - { "ActionForward", "#{sForward}" }, - { "ActionCrouch", "#{sCrouch_Sneak}" }, - { "ActionJump", "#{sJump}" }, - { "ActionBack", "#{sBack}" }, - { "ActionUse", "#{sUse}" }, - { "ActionRun", "#{sRun}" }, + { "actionslideright", "#{sRight}" }, + { "actionreadymagic", "#{sReady_Magic}" }, + { "actionprevweapon", "#{sPrevWeapon}" }, + { "actionnextweapon", "#{sNextWeapon}" }, + { "actiontogglerun", "#{sAuto_Run}" }, + { "actionslideleft", "#{sLeft}" }, + { "actionreadyitem", "#{sReady_Weapon}" }, + { "actionprevspell", "#{sPrevSpell}" }, + { "actionnextspell", "#{sNextSpell}" }, + { "actionrestmenu", "#{sRestKey}" }, + { "actionmenumode", "#{sInventory}" }, + { "actionactivate", "#{sActivate}" }, + { "actionjournal", "#{sJournal}" }, + { "actionforward", "#{sForward}" }, + { "actioncrouch", "#{sCrouch_Sneak}" }, + { "actionjump", "#{sJump}" }, + { "actionback", "#{sBack}" }, + { "actionuse", "#{sUse}" }, + { "actionrun", "#{sRun}" }, }; using ContextMethod = std::string_view (Interpreter::Context::*)() const; const std::initializer_list>> sContextMethods{ - { "NextPCRank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "PCNextRank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "Faction", { &Interpreter::Context::getNPCFaction, nullptr } }, - { "PCClass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, - { "PCName", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, - { "PCRace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, - { "PCRank", { &Interpreter::Context::getPCRank, nullptr } }, - { "Class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, - { "Cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, - { "Race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, - { "Rank", { &Interpreter::Context::getNPCRank, nullptr } }, - { "Name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, + { "nextpcrank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "pcnextrank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "faction", { &Interpreter::Context::getNPCFaction, nullptr } }, + { "pcclass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, + { "pcname", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, + { "pcrace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, + { "pcrank", { &Interpreter::Context::getPCRank, nullptr } }, + { "class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, + { "cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, + { "race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, + { "rank", { &Interpreter::Context::getNPCRank, nullptr } }, + { "name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, }; bool longerStr(std::string_view a, std::string_view b) @@ -78,7 +78,7 @@ namespace return true; } } - if (check(temp, "PCCrimeLevel", i, start)) + if (check(temp, "pccrimelevel", i, start)) { retval << context.getPCBounty(); return true; @@ -89,13 +89,7 @@ namespace if (check(temp, name, i, start)) { if (method) // Not all variables are available outside of dialogue - { retval << (context.*method)(); - - // Re-add the token if replacement failed without an error - if ((context.*method)() == "%") - retval << name; - } return true; } } From 08923572308277f184edd91d7aef0fc7d91449a2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 8 Jul 2025 20:32:20 +0300 Subject: [PATCH 14/29] Only autoequip the shield in updateEquippedLight (#8404) --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1e62cc4a21..b418515bf7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1066,9 +1066,12 @@ namespace MWMechanics { if (heldIter != inventoryStore.end() && heldIter->getType() == ESM::Light::sRecordId) { - // At day, unequip lights and auto equip shields or other suitable items - // (Note: autoEquip will ignore lights) - inventoryStore.autoEquip(); + // At day, unequip lights and auto equip shields + auto shield = inventoryStore.getPreferredShield(); + if (shield != inventoryStore.end()) + inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, shield); + else + inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft); } } } From f3420bd1bd00135e222b18ac69c1310686a91136 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 9 Jul 2025 10:55:17 +0300 Subject: [PATCH 15/29] Move Quitting peacefully message to a more appropriate place --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 29cfb41071..5807ef222b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -433,6 +433,8 @@ OMW::Engine::~Engine() } SDL_Quit(); + + Log(Debug::Info) << "Quitting peacefully."; } // Set data dir @@ -1069,8 +1071,6 @@ void OMW::Engine::go() Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); Settings::ShaderManager::get().save(); mLuaManager->savePermanentStorage(mCfgMgr.getUserConfigPath()); - - Log(Debug::Info) << "Quitting peacefully."; } void OMW::Engine::setCompileAll(bool all) From fe7970421f8b6a07a92026912987dbfeb17433c2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 11 Jul 2025 11:10:02 +0300 Subject: [PATCH 16/29] Don't harvest if player activation is blocked (#8612) --- apps/openmw/mwclass/container.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c8b1f05972..fff191c22d 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -192,12 +192,13 @@ namespace MWClass { if (!isTrapped) { - if (canBeHarvested(ptr)) - { - return std::make_unique(ptr); - } + if (!canBeHarvested(ptr)) + return std::make_unique(ptr); - return std::make_unique(ptr); + if (hasToolTip(ptr)) + return std::make_unique(ptr); + + return std::make_unique(std::string_view{}, ptr); } else { From 61ebb4b259652f4267af0f47e12b3936ed318813 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:07:49 -0600 Subject: [PATCH 17/29] Redo debug warnings in interpreter --- apps/openmw/mwscript/interpretercontext.cpp | 66 ++++++++++++++------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 15c9100b98..3063e8b6bb 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -300,7 +301,16 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const ESM::NPC* npc = getReferenceImp().get()->mBase; + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + + const ESM::NPC* npc = ptr.get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -308,18 +318,26 @@ namespace MWScript std::string_view InterpreterContext::getNPCRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); - if (faction.empty()) - throw std::runtime_error("getNPCRank(): NPC is not in a faction"); - - int rank = ptr.getClass().getPrimaryFactionRank(ptr); - if (rank < 0 || rank > 9) - throw std::runtime_error("getNPCRank(): invalid rank"); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ESMStore& store = world->getStore(); - const ESM::Faction* fact = store.get().find(faction); - return fact->mRanks[rank]; + const ESM::Faction* faction = store.get().find(factionId); + + int rank = ptrClass.getPrimaryFactionRank(ptr); + if (rank < 0 || rank > 9) + { + Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has invalid rank " << rank + << " in faction " << faction->mName; + return "%"; + } + return faction->mRanks[rank]; } std::string_view InterpreterContext::getPCName() const @@ -344,13 +362,17 @@ namespace MWScript std::string_view InterpreterContext::getPCRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - - const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); - if (factionId.empty()) - throw std::runtime_error("getPCRank(): NPC is not in a faction"); - const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); int rank = -1; @@ -373,13 +395,17 @@ namespace MWScript std::string_view InterpreterContext::getPCNextRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - - const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); - if (factionId.empty()) - throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); - const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); int rank = -1; From cef180753667b0e0eab744cf099c02ea6218caa2 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:30:55 -0600 Subject: [PATCH 18/29] Use RefId instead of name --- apps/openmw/mwscript/interpretercontext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 3063e8b6bb..dbd139d180 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -306,7 +306,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCFaction(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -322,7 +322,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -333,7 +333,7 @@ namespace MWScript int rank = ptrClass.getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has invalid rank " << rank + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank << " in faction " << faction->mName; return "%"; } @@ -367,7 +367,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -400,7 +400,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCNextRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } From 87e41425bb1bb7e6cb9e4fedf801eb4b20cdc4df Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:36:16 -0600 Subject: [PATCH 19/29] Unnecessary ptrClass --- apps/openmw/mwscript/interpretercontext.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index dbd139d180..d24420ec91 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -302,8 +302,7 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; @@ -363,8 +362,7 @@ namespace MWScript std::string_view InterpreterContext::getPCRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; @@ -396,8 +394,7 @@ namespace MWScript std::string_view InterpreterContext::getPCNextRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; From 11947286d937e41c572e420a0eca709305e2d82e Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:36:59 -0600 Subject: [PATCH 20/29] Reuse factionId --- apps/openmw/mwscript/interpretercontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d24420ec91..7d71f3607c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -309,8 +309,9 @@ namespace MWScript return "%"; } - const ESM::NPC* npc = ptr.get()->mBase; - const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore& store = world->getStore(); + const ESM::Faction* faction = store.get().find(factionId); return faction->mName; } From bb1214ed69f855874f9fc13296cb65025e26b3c7 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:48:37 -0600 Subject: [PATCH 21/29] factionId instead of faction->mName --- apps/openmw/mwscript/interpretercontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 7d71f3607c..546968ebf7 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -334,7 +334,7 @@ namespace MWScript if (rank < 0 || rank > 9) { Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank - << " in faction " << faction->mName; + << " in faction " << factionId; return "%"; } return faction->mRanks[rank]; From 445cf1742de45836350bcff0ce560c6df6f15af0 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 10:20:58 -0600 Subject: [PATCH 22/29] ptr.getCellRef().getRefId() --- apps/openmw/mwscript/interpretercontext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 546968ebf7..f6c20c9c10 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -305,7 +305,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -322,7 +322,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -333,7 +333,7 @@ namespace MWScript int rank = ptrClass.getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.getCellRef().getRefId() << " has invalid rank " << rank << " in faction " << factionId; return "%"; } @@ -366,7 +366,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getPCRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -398,7 +398,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } From 682f00bcff932cf5226b880e3b893af95a24c63a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 13 Jul 2025 18:36:30 +0200 Subject: [PATCH 23/29] Don't play down sound while loading quick keys --- apps/openmw/mwgui/quickkeysmenu.cpp | 8 ++++++-- apps/openmw/mwgui/quickkeysmenu.hpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 93f98a295f..3c62400e0d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -228,7 +228,7 @@ namespace MWGui mAssignDialog->setVisible(false); } - void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) + void QuickKeysMenu::assignItem(MWWorld::Ptr item) { assert(mSelected); @@ -245,7 +245,11 @@ namespace MWGui if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); + } + void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) + { + assignItem(item); MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item)); } @@ -566,7 +570,7 @@ namespace MWGui else { if (quickKey.mType == ESM::QuickKeys::Type::Item) - onAssignItem(item); + assignItem(item); else // if (quickKey.mType == ESM::QuickKeys::Type::MagicItem) onAssignMagicItem(item); } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 904029b9a0..a43cce50b4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -72,6 +72,7 @@ namespace MWGui // Check if quick key is still valid inline void validate(int index); void unassign(keyData* key); + void assignItem(MWWorld::Ptr item); }; class QuickKeysMenuAssign : public WindowModal From a03a2a5ff2a268f3d6a646f07a6922cdc63d7e05 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 13 Jul 2025 19:20:44 +0300 Subject: [PATCH 24/29] Re-reimplement TCB interpolation for scalars and vectors (#2379) --- components/nif/nifkey.hpp | 82 +++++++++++++++++++++++--------- components/nifosg/controller.hpp | 2 +- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 604cf92c33..5a755c8d0d 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -4,6 +4,7 @@ #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP #include +#include #include "exception.hpp" #include "niffile.hpp" @@ -17,7 +18,7 @@ namespace Nif InterpolationType_Unknown = 0, InterpolationType_Linear = 1, InterpolationType_Quadratic = 2, - InterpolationType_TBC = 3, + InterpolationType_TCB = 3, InterpolationType_XYZ = 4, InterpolationType_Constant = 5 }; @@ -28,18 +29,19 @@ namespace Nif T mValue; T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - - // FIXME: Implement TBC interpolation - /* - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation - */ }; - using FloatKey = KeyT; - using Vector3Key = KeyT; - using Vector4Key = KeyT; - using QuaternionKey = KeyT; + + template + struct TCBKey + { + float mTime; + T mValue{}; + T mInTan{}; + T mOutTan{}; + float mTension; + float mContinuity; + float mBias; + }; template struct KeyMapT @@ -101,15 +103,20 @@ namespace Nif mKeys[time] = key; } } - else if (mInterpolationType == InterpolationType_TBC) + else if (mInterpolationType == InterpolationType_TCB) { - for (size_t i = 0; i < count; i++) + std::vector> tcbKeys(count); + for (TCBKey& tcbKey : tcbKeys) { - float time; - nif->read(time); - readTBC(*nif, key); - mKeys[time] = key; + nif->read(tcbKey.mTime); + tcbKey.mValue = ((*nif).*getValue)(); + nif->read(tcbKey.mTension); + nif->read(tcbKey.mContinuity); + nif->read(tcbKey.mBias); } + generateTCBTangents(tcbKeys); + for (TCBKey& key : tcbKeys) + mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; } else if (mInterpolationType == InterpolationType_XYZ) { @@ -140,14 +147,43 @@ namespace Nif static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } - static void readTBC(NIFStream& nif, KeyT& key) + template + static void generateTCBTangents(std::vector>& keys) { - readValue(nif, key); - /*key.mTension = */ nif.get(); - /*key.mBias = */ nif.get(); - /*key.mContinuity = */ nif.get(); + if (keys.size() <= 1) + return; + + for (std::size_t i = 0; i < keys.size(); ++i) + { + TCBKey& curr = keys[i]; + const TCBKey* prev = (i == 0) ? nullptr : &keys[i - 1]; + const TCBKey* next = (i == keys.size() - 1) ? nullptr : &keys[i + 1]; + const float prevLen = prev != nullptr && next != nullptr ? curr.mTime - prev->mTime : 1.f; + const float nextLen = prev != nullptr && next != nullptr ? next->mTime - curr.mTime : 1.f; + if (prevLen + nextLen == 0.f) + continue; + const float x = (1.f - curr.mTension) * (1.f - curr.mContinuity) * (1.f + curr.mBias); + const float y = (1.f - curr.mTension) * (1.f + curr.mContinuity) * (1.f - curr.mBias); + const float z = (1.f - curr.mTension) * (1.f + curr.mContinuity) * (1.f + curr.mBias); + const float w = (1.f - curr.mTension) * (1.f - curr.mContinuity) * (1.f - curr.mBias); + const U prevDelta = prev != nullptr ? curr.mValue - prev->mValue : next->mValue - curr.mValue; + const U nextDelta = next != nullptr ? next->mValue - curr.mValue : curr.mValue - prev->mValue; + curr.mInTan = (prevDelta * x + nextDelta * y) * prevLen / (prevLen + nextLen); + curr.mOutTan = (prevDelta * z + nextDelta * w) * nextLen / (prevLen + nextLen); + } + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: is this even legal? + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: implement TCB interpolation for quaternions } }; + using FloatKeyMap = KeyMapT>; using Vector3KeyMap = KeyMapT>; using Vector4KeyMap = KeyMapT>; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 99d3df9545..468668ce76 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -131,6 +131,7 @@ namespace NifOsg case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; case Nif::InterpolationType_Quadratic: + case Nif::InterpolationType_TCB: { // Using a cubic Hermite spline. // b1(t) = 2t^3 - 3t^2 + 1 @@ -147,7 +148,6 @@ namespace NifOsg const float b4 = t3 - t2; return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; } - // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); } From 6f9b813bd1da8cbb9896e42fffb5a5db0644877d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 14 Jul 2025 22:39:19 +0200 Subject: [PATCH 25/29] Mark scripts on newly scripted, active objects as active --- apps/openmw/mwlua/localscripts.cpp | 13 ++++++++----- apps/openmw/mwlua/localscripts.hpp | 2 +- apps/openmw/mwlua/luamanagerimp.cpp | 3 +++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 4bdfb0d13a..d784328035 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -235,13 +235,16 @@ namespace MWLua &mOnSkillLevelUp }); } - void LocalScripts::setActive(bool active) + void LocalScripts::setActive(bool active, bool callHandlers) { mData.mIsActive = active; - if (active) - callEngineHandlers(mOnActiveHandlers); - else - callEngineHandlers(mOnInactiveHandlers); + if (callHandlers) + { + if (active) + callEngineHandlers(mOnActiveHandlers); + else + callEngineHandlers(mOnInactiveHandlers); + } } void LocalScripts::applyStatsCache() diff --git a/apps/openmw/mwlua/localscripts.hpp b/apps/openmw/mwlua/localscripts.hpp index adbf20292d..146eff95ba 100644 --- a/apps/openmw/mwlua/localscripts.hpp +++ b/apps/openmw/mwlua/localscripts.hpp @@ -67,7 +67,7 @@ namespace MWLua MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; } const MWWorld::Ptr& getPtrOrEmpty() const { return mData.ptrOrEmpty(); } - void setActive(bool active); + void setActive(bool active, bool callHandlers = true); bool isActive() const override { return mData.mIsActive; } void onConsume(const LObject& consumable) { callEngineHandlers(mOnConsumeHandlers, consumable); } void onActivated(const LObject& actor) { callEngineHandlers(mOnActivatedHandlers, actor); } diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 5fa2d9867c..2fd7618ad7 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -540,7 +540,10 @@ namespace MWLua localScripts = createLocalScripts(ptr); localScripts->addAutoStartedScripts(); if (ptr.isInCell() && MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell())) + { + localScripts->setActive(true, false); mActiveLocalScripts.insert(localScripts); + } } localScripts->addCustomScript(scriptId, initData); } From 8826d5cb0e7dbb3ddbdad79601d2f0681a46222e Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 15 Jul 2025 15:04:39 +0300 Subject: [PATCH 26/29] Update project leader history --- AUTHORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e327bc29d6..51910dedaa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -10,7 +10,8 @@ If you feel your name is missing from this list, please add it to `AUTHORS.md`. Programmers ----------- - Bret Curtis (psi29a) - Project leader 2019-present + Alexey Dobrokhotov (Capo) - Project leader 2025-present + Bret Curtis (psi29a) - Project leader 2019-2025 Marc Zinnschlag (Zini) - Project leader 2010-2018 Nicolay Korslund - Project leader 2008-2010 scrawl - Top contributor @@ -49,7 +50,6 @@ Programmers Berulacks Bo Svensson Britt Mathis (galdor557) - Capostrophic Carl Maxwell cc9cii Cédric Mocquillon From d602e9ff7a70175e23a4f8718450e3a89d573e59 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 15 Jul 2025 18:05:32 +0300 Subject: [PATCH 27/29] Don't build the engine, the editor and editor tests multiple times in Clang Tidy jobs --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1ca0d4251e..8d1e19d462 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -414,7 +414,7 @@ Ubuntu_Clang_Tidy_openmw: needs: - Ubuntu_Clang_Tidy_components variables: - BUILD_TARGETS: openmw + BUILD_TARGETS: openmw openmw-tests timeout: 3h Ubuntu_Clang_Tidy_openmw-cs: @@ -430,7 +430,7 @@ Ubuntu_Clang_Tidy_other: needs: - Ubuntu_Clang_Tidy_components variables: - BUILD_TARGETS: bsatool esmtool openmw-launcher openmw-iniimporter openmw-essimporter openmw-wizard niftest components-tests openmw-tests openmw-cs-tests openmw-navmeshtool openmw-bulletobjecttool + BUILD_TARGETS: components-tests bsatool esmtool openmw-launcher openmw-iniimporter openmw-essimporter openmw-wizard niftest openmw-navmeshtool openmw-bulletobjecttool timeout: 3h .Ubuntu_Clang_tests: From f9c7dc0b20037165e96a7b3e9c75675f084f440d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Mon, 14 Jul 2025 19:42:00 +0300 Subject: [PATCH 28/29] Sync changelog for 0.50.0 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e847ec69fd..5435835606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,21 @@ Bug #6039: Next Spell keybind fails while selected enchanted item has multiple copies Bug #6573: Editor: Selection behaves incorrectly on high-DPI displays Bug #6792: Birth sign info box has no line breaks + Bug #7371: Equipping item from inventory does not play a Down sound when equipping fails Bug #7622: Player's marksman weapons don't work on close actors underwater + Bug #7649: The sound and vfx of resisted enchanted items' magic still play Bug #7740: Magic items in the HUD aren't composited correctly Bug #7799: Picking up ingredients while object paging active grid is on may cause a hiccup + Bug #7871: Kwama Queen doesn't start combat with player Bug #8245: The console command ShowVars does not list global mwscripts Bug #8265: Topics are linked incorrectly Bug #8303: On target spells cast by non-actors should fire underwater Bug #8318: Missing global variables are not handled gracefully in dialogue conditions + Bug #8333: Quest status subrecords should not actually cause parsing to skip remaining data Bug #8340: Multi-effect enchantments are too expensive Bug #8341: Repeat shader visitor passes discard parallax Bug #8349: Travel to non-existent cell causes persistent black screen + Bug #8359: Some quick keys menu related issues Bug #8371: Silence affects powers Bug #8375: Moon phase cycle doesn't match Morrowind Bug #8383: Casting bound helm or boots on beast races doesn't cleanup properly @@ -38,12 +43,19 @@ Bug #8593: Render targets do not generate mipmaps Bug #8598: Post processing shaders don't interact with the vfs correctly Bug #8599: Non-ASCII paths in BSA files don't work + Bug #8609: The crosshair is too large + Bug #8610: Terrain normal maps using NormalGL format instead of NormalDX + Bug #8612: Using aiactivate on an ingredient when graphical herbalism is enabled triggers non-stop pickup sounds + Bug #8615: Rest/wait time progress speed is different from vanilla + Feature #2522: Support quick item transfer Feature #3769: Allow GetSpellEffects on enchantments Feature #8112: Expose landscape record data to Lua Feature #8113: Support extended selection in autodetected subdirectory dialog + Feature #8139: Editor: Redesign the selection markers Feature #8285: Expose list of active shaders in postprocessing API Feature #8313: Show the character name in the savegame details Feature #8320: Add access mwscript source text to lua api + Feature #8334: Lua: AddTopic equivalent Feature #8355: Lua: Window visibility checking in interfaces.UI Feature #8580: Sort characters in the save loading menu Feature #8597: Lua: Add more built-in event handlers From f45053ad25f2fb13d15e11022378cb2d95e763b1 Mon Sep 17 00:00:00 2001 From: Andy Lanzone Date: Thu, 17 Jul 2025 07:20:13 -0700 Subject: [PATCH 29/29] Bump libsdl to 2.0.20 --- CMakeLists.txt | 2 +- apps/openmw/mwinput/controllermanager.cpp | 4 ---- components/sdlutil/events.hpp | 2 -- components/sdlutil/sdlinputwrapper.cpp | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a00dafc7ef..902f89ec27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -466,7 +466,7 @@ find_package(Boost 1.70.0 CONFIG REQUIRED COMPONENTS ${BOOST_COMPONENTS} OPTIONA if(OPENMW_USE_SYSTEM_MYGUI) find_package(MyGUI 3.4.3 REQUIRED) endif() -find_package(SDL2 2.0.10 REQUIRED) +find_package(SDL2 2.0.20 REQUIRED) find_package(OpenAL REQUIRED) find_package(ZLIB REQUIRED) diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 1a8490d8b7..0bba8bfa32 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -349,7 +349,6 @@ namespace MWInput void ControllerManager::enableGyroSensor() { mGyroAvailable = false; -#if SDL_VERSION_ATLEAST(2, 0, 14) SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); if (!cntrl) return; @@ -361,7 +360,6 @@ namespace MWInput return; } mGyroAvailable = true; -#endif } bool ControllerManager::isGyroAvailable() const @@ -372,7 +370,6 @@ namespace MWInput std::array ControllerManager::getGyroValues() const { float gyro[3] = { 0.f }; -#if SDL_VERSION_ATLEAST(2, 0, 14) SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); if (cntrl && mGyroAvailable) { @@ -380,7 +377,6 @@ namespace MWInput if (result < 0) Log(Debug::Error) << "Failed to get game controller sensor data: " << SDL_GetError(); } -#endif return std::array({ gyro[0], gyro[1], gyro[2] }); } diff --git a/components/sdlutil/events.hpp b/components/sdlutil/events.hpp index 3ae15e448c..410ee68440 100644 --- a/components/sdlutil/events.hpp +++ b/components/sdlutil/events.hpp @@ -28,7 +28,6 @@ namespace SDLUtil float mY; float mPressure; -#if SDL_VERSION_ATLEAST(2, 0, 14) explicit TouchEvent(const SDL_ControllerTouchpadEvent& arg) : mDevice(arg.touchpad) , mFinger(arg.finger) @@ -37,7 +36,6 @@ namespace SDLUtil , mPressure(arg.pressure) { } -#endif }; /////////////// diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 41a4f13818..104f83fc6d 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -173,7 +173,6 @@ namespace SDLUtil if (mConListener) mConListener->axisMoved(1, evt.caxis); break; -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_CONTROLLERSENSORUPDATE: // controller sensor data is received on demand break; @@ -186,7 +185,6 @@ namespace SDLUtil case SDL_CONTROLLERTOUCHPADUP: mConListener->touchpadReleased(1, TouchEvent(evt.ctouchpad)); break; -#endif case SDL_WINDOWEVENT: handleWindowEvent(evt); break;