Merge branch 'topicloop' into 'master'

Detect service refusal in constant time

See merge request OpenMW/openmw!3053
simplify_debugging
psi29a 1 year ago
commit 30305d7bea

@ -159,12 +159,12 @@ namespace MWDialogue
Filter filter(actor, mChoice, mTalkedTo);
for (MWWorld::Store<ESM::Dialogue>::iterator it = dialogs.begin(); it != dialogs.end(); ++it)
for (const ESM::Dialogue& dialogue : dialogs)
{
if (it->mType == ESM::Dialogue::Greeting)
if (dialogue.mType == ESM::Dialogue::Greeting)
{
// Search a response (we do not accept a fallback to "Info refusal" here)
if (const ESM::DialInfo* info = filter.search(*it, false))
if (const ESM::DialInfo* info = filter.search(dialogue, false).second)
{
creatureStats.talkedToPlayer();
@ -176,7 +176,7 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(), mActor);
callback->addResponse({}, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript(info->mResultScript, mActor);
mLastTopic = it->mId;
mLastTopic = dialogue.mId;
addTopicsFromText(info->mResponse);
@ -291,11 +291,11 @@ namespace MWDialogue
const ESM::Dialogue& dialogue = *dialogues.find(topic);
const ESM::DialInfo* info = filter.search(dialogue, true);
const auto [responseTopic, info] = filter.search(dialogue, true);
if (info)
{
std::string title;
std::string_view title;
if (dialogue.mType == ESM::Dialogue::Persuasion)
{
// Determine GMST from dialogue topic. GMSTs are:
@ -320,15 +320,8 @@ namespace MWDialogue
{
// Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info
// refusal group, in which case it should not be added to the journal.
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin();
iter != dialogue.mInfo.end(); ++iter)
{
if (iter->mId == info->mId)
{
MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, mActor);
break;
}
}
if (responseTopic == &dialogue)
MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, mActor);
}
mLastTopic = topic;
@ -363,7 +356,7 @@ namespace MWDialogue
{
if (dialog.mType == ESM::Dialogue::Topic)
{
const auto* answer = filter.search(dialog, true);
const auto* answer = filter.search(dialog, true).second;
const auto& topicId = dialog.mId;
if (answer != nullptr)
@ -477,9 +470,10 @@ namespace MWDialogue
if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting)
{
if (const ESM::DialInfo* info = filter.search(*dialogue, true))
const auto [responseTopic, info] = filter.search(*dialogue, true);
if (info)
{
std::string text = info->mResponse;
const std::string& text = info->mResponse;
addTopicsFromText(text);
mChoice = -1;
@ -493,15 +487,8 @@ namespace MWDialogue
{
// Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the
// Info refusal group, in which case it should not be added to the journal
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin();
iter != dialogue->mInfo.end(); ++iter)
{
if (iter->mId == info->mId)
{
MWBase::Environment::get().getJournal()->addTopic(mLastTopic, info->mId, mActor);
break;
}
}
if (responseTopic == dialogue)
MWBase::Environment::get().getJournal()->addTopic(mLastTopic, info->mId, mActor);
}
executeScript(info->mResultScript, mActor);
@ -609,10 +596,10 @@ namespace MWDialogue
const ESM::Dialogue& dialogue = *dialogues.find(ESM::RefId::stringRefId("Service Refusal"));
std::vector<const ESM::DialInfo*> infos = filter.list(dialogue, false, false, true);
std::vector<Filter::Response> infos = filter.list(dialogue, false, false, true);
if (!infos.empty())
{
const ESM::DialInfo* info = infos[0];
const ESM::DialInfo* info = infos[0].second;
addTopicsFromText(info->mResponse);
@ -656,7 +643,7 @@ namespace MWDialogue
const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
Filter filter(actor, 0, creatureStats.hasTalkedToPlayer());
const ESM::DialInfo* info = filter.search(*dial, false);
const ESM::DialInfo* info = filter.search(*dial, false).second;
if (info != nullptr)
{
MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager();
@ -697,10 +684,9 @@ namespace MWDialogue
ESM::DialogueState state;
state.load(reader);
for (std::vector<ESM::RefId>::const_iterator iter(state.mKnownTopics.begin());
iter != state.mKnownTopics.end(); ++iter)
if (store.get<ESM::Dialogue>().search(*iter))
mKnownTopics.insert(*iter);
for (const auto& knownTopic : state.mKnownTopics)
if (store.get<ESM::Dialogue>().search(knownTopic))
mKnownTopics.insert(knownTopic);
mChangedFactionReaction = state.mChangedFactionReaction;
}

@ -678,12 +678,13 @@ MWDialogue::Filter::Filter(const MWWorld::Ptr& actor, int choice, bool talkedToP
{
}
const ESM::DialInfo* MWDialogue::Filter::search(const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
MWDialogue::Filter::Response MWDialogue::Filter::search(
const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
{
std::vector<const ESM::DialInfo*> suitableInfos = list(dialogue, fallbackToInfoRefusal, false);
auto suitableInfos = list(dialogue, fallbackToInfoRefusal, false);
if (suitableInfos.empty())
return nullptr;
return {};
else
return suitableInfos[0];
}
@ -693,22 +694,21 @@ bool MWDialogue::Filter::couldPotentiallyMatch(const ESM::DialInfo& info) const
return testActor(info) && matchesStaticFilters(info, mActor);
}
std::vector<const ESM::DialInfo*> MWDialogue::Filter::list(
std::vector<MWDialogue::Filter::Response> MWDialogue::Filter::list(
const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition) const
{
std::vector<const ESM::DialInfo*> infos;
std::vector<MWDialogue::Filter::Response> infos;
bool infoRefusal = false;
// Iterate over topic responses to find a matching one
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter != dialogue.mInfo.end();
++iter)
for (const auto& info : dialogue.mInfo)
{
if (testActor(*iter) && testPlayer(*iter) && testSelectStructs(*iter))
if (testActor(info) && testPlayer(info) && testSelectStructs(info))
{
if (testDisposition(*iter, invertDisposition))
if (testDisposition(info, invertDisposition))
{
infos.push_back(&*iter);
infos.emplace_back(&dialogue, &info);
if (!searchAll)
break;
}
@ -726,12 +726,11 @@ std::vector<const ESM::DialInfo*> MWDialogue::Filter::list(
const ESM::Dialogue& infoRefusalDialogue = *dialogues.find(ESM::RefId::stringRefId("Info Refusal"));
for (ESM::Dialogue::InfoContainer::const_iterator iter = infoRefusalDialogue.mInfo.begin();
iter != infoRefusalDialogue.mInfo.end(); ++iter)
if (testActor(*iter) && testPlayer(*iter) && testSelectStructs(*iter)
&& testDisposition(*iter, invertDisposition))
for (const auto& info : infoRefusalDialogue.mInfo)
if (testActor(info) && testPlayer(info) && testSelectStructs(info)
&& testDisposition(info, invertDisposition))
{
infos.push_back(&*iter);
infos.emplace_back(&dialogue, &info);
if (!searchAll)
break;
}

@ -1,6 +1,7 @@
#ifndef GAME_MWDIALOGUE_FILTER_H
#define GAME_MWDIALOGUE_FILTER_H
#include <utility>
#include <vector>
#include "../mwworld/ptr.hpp"
@ -52,10 +53,12 @@ namespace MWDialogue
const MWWorld::Ptr& actor, const ESM::RefId& factionId, int rank) const;
public:
using Response = std::pair<const ESM::Dialogue*, const ESM::DialInfo*>;
Filter(const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
std::vector<const ESM::DialInfo*> list(const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal,
bool searchAll, bool invertDisposition = false) const;
std::vector<Response> list(const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll,
bool invertDisposition = false) const;
///< List all infos that could be used on the given actor, using the current runtime state of the actor.
/// \note If fallbackToInfoRefusal is used, the returned DialInfo might not be from the supplied ESM::Dialogue.
@ -63,7 +66,7 @@ namespace MWDialogue
///< Check if this INFO could potentially be said by the given actor, ignoring runtime state filters and
///< ignoring player filters.
const ESM::DialInfo* search(const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
Response search(const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
///< Get a matching response for the requested dialogue.
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
};

Loading…
Cancel
Save