diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 6511fbdb01..6c219a52a3 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -82,6 +82,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 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) + { + if (dialogue.mType == ESM::Dialogue::Type::Journal) + { + for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) + { + if (journalInfo.mQuestStatus != ESM::DialInfo::QS_Name) + journal->addEntry(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, playerPtr); + } + dialogueManager->addTopic(dialogue.mId); + } + } + } + }; + class OpAddTopic : public Interpreter::Opcode0 { public: @@ -288,6 +321,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/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 15c9100b98..f6c20c9c10 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,26 +301,43 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const ESM::NPC* npc = getReferenceImp().get()->mBase; - const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); + const MWWorld::Ptr& ptr = getReferenceImp(); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; + return "%"; + } + + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore& store = world->getStore(); + const ESM::Faction* faction = store.get().find(factionId); return faction->mName; } 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 " << ptr.getCellRef().getRefId() << " 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 " << ptr.getCellRef().getRefId() << " has invalid rank " << rank + << " in faction " << factionId; + return "%"; + } + return faction->mRanks[rank]; } std::string_view InterpreterContext::getPCName() const @@ -344,13 +362,16 @@ namespace MWScript std::string_view InterpreterContext::getPCRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCRank(): NPC " << ptr.getCellRef().getRefId() << " 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 +394,16 @@ namespace MWScript std::string_view InterpreterContext::getPCNextRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.getCellRef().getRefId() << " 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; 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;