mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-10 15:45:37 +00:00
Merge branch 'topicloop' into 'master'
Detect service refusal in constant time See merge request OpenMW/openmw!3053
This commit is contained in:
commit
30305d7bea
@ -159,12 +159,12 @@ namespace MWDialogue
|
|||||||
|
|
||||||
Filter filter(actor, mChoice, mTalkedTo);
|
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)
|
// 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();
|
creatureStats.talkedToPlayer();
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ namespace MWDialogue
|
|||||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(), mActor);
|
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(), mActor);
|
||||||
callback->addResponse({}, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
callback->addResponse({}, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||||
executeScript(info->mResultScript, mActor);
|
executeScript(info->mResultScript, mActor);
|
||||||
mLastTopic = it->mId;
|
mLastTopic = dialogue.mId;
|
||||||
|
|
||||||
addTopicsFromText(info->mResponse);
|
addTopicsFromText(info->mResponse);
|
||||||
|
|
||||||
@ -291,11 +291,11 @@ namespace MWDialogue
|
|||||||
|
|
||||||
const ESM::Dialogue& dialogue = *dialogues.find(topic);
|
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)
|
if (info)
|
||||||
{
|
{
|
||||||
std::string title;
|
std::string_view title;
|
||||||
if (dialogue.mType == ESM::Dialogue::Persuasion)
|
if (dialogue.mType == ESM::Dialogue::Persuasion)
|
||||||
{
|
{
|
||||||
// Determine GMST from dialogue topic. GMSTs are:
|
// 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
|
// 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.
|
// refusal group, in which case it should not be added to the journal.
|
||||||
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin();
|
if (responseTopic == &dialogue)
|
||||||
iter != dialogue.mInfo.end(); ++iter)
|
MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, mActor);
|
||||||
{
|
|
||||||
if (iter->mId == info->mId)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, mActor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastTopic = topic;
|
mLastTopic = topic;
|
||||||
@ -363,7 +356,7 @@ namespace MWDialogue
|
|||||||
{
|
{
|
||||||
if (dialog.mType == ESM::Dialogue::Topic)
|
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;
|
const auto& topicId = dialog.mId;
|
||||||
|
|
||||||
if (answer != nullptr)
|
if (answer != nullptr)
|
||||||
@ -477,9 +470,10 @@ namespace MWDialogue
|
|||||||
|
|
||||||
if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting)
|
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);
|
addTopicsFromText(text);
|
||||||
|
|
||||||
mChoice = -1;
|
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
|
// 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
|
// Info refusal group, in which case it should not be added to the journal
|
||||||
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin();
|
if (responseTopic == dialogue)
|
||||||
iter != dialogue->mInfo.end(); ++iter)
|
MWBase::Environment::get().getJournal()->addTopic(mLastTopic, info->mId, mActor);
|
||||||
{
|
|
||||||
if (iter->mId == info->mId)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getJournal()->addTopic(mLastTopic, info->mId, mActor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executeScript(info->mResultScript, mActor);
|
executeScript(info->mResultScript, mActor);
|
||||||
@ -609,10 +596,10 @@ namespace MWDialogue
|
|||||||
|
|
||||||
const ESM::Dialogue& dialogue = *dialogues.find(ESM::RefId::stringRefId("Service Refusal"));
|
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())
|
if (!infos.empty())
|
||||||
{
|
{
|
||||||
const ESM::DialInfo* info = infos[0];
|
const ESM::DialInfo* info = infos[0].second;
|
||||||
|
|
||||||
addTopicsFromText(info->mResponse);
|
addTopicsFromText(info->mResponse);
|
||||||
|
|
||||||
@ -656,7 +643,7 @@ namespace MWDialogue
|
|||||||
|
|
||||||
const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
||||||
Filter filter(actor, 0, creatureStats.hasTalkedToPlayer());
|
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)
|
if (info != nullptr)
|
||||||
{
|
{
|
||||||
MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager();
|
MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager();
|
||||||
@ -697,10 +684,9 @@ namespace MWDialogue
|
|||||||
ESM::DialogueState state;
|
ESM::DialogueState state;
|
||||||
state.load(reader);
|
state.load(reader);
|
||||||
|
|
||||||
for (std::vector<ESM::RefId>::const_iterator iter(state.mKnownTopics.begin());
|
for (const auto& knownTopic : state.mKnownTopics)
|
||||||
iter != state.mKnownTopics.end(); ++iter)
|
if (store.get<ESM::Dialogue>().search(knownTopic))
|
||||||
if (store.get<ESM::Dialogue>().search(*iter))
|
mKnownTopics.insert(knownTopic);
|
||||||
mKnownTopics.insert(*iter);
|
|
||||||
|
|
||||||
mChangedFactionReaction = state.mChangedFactionReaction;
|
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())
|
if (suitableInfos.empty())
|
||||||
return nullptr;
|
return {};
|
||||||
else
|
else
|
||||||
return suitableInfos[0];
|
return suitableInfos[0];
|
||||||
}
|
}
|
||||||
@ -693,22 +694,21 @@ bool MWDialogue::Filter::couldPotentiallyMatch(const ESM::DialInfo& info) const
|
|||||||
return testActor(info) && matchesStaticFilters(info, mActor);
|
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
|
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;
|
bool infoRefusal = false;
|
||||||
|
|
||||||
// Iterate over topic responses to find a matching one
|
// Iterate over topic responses to find a matching one
|
||||||
for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter != dialogue.mInfo.end();
|
for (const auto& info : dialogue.mInfo)
|
||||||
++iter)
|
|
||||||
{
|
{
|
||||||
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)
|
if (!searchAll)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -726,12 +726,11 @@ std::vector<const ESM::DialInfo*> MWDialogue::Filter::list(
|
|||||||
|
|
||||||
const ESM::Dialogue& infoRefusalDialogue = *dialogues.find(ESM::RefId::stringRefId("Info Refusal"));
|
const ESM::Dialogue& infoRefusalDialogue = *dialogues.find(ESM::RefId::stringRefId("Info Refusal"));
|
||||||
|
|
||||||
for (ESM::Dialogue::InfoContainer::const_iterator iter = infoRefusalDialogue.mInfo.begin();
|
for (const auto& info : infoRefusalDialogue.mInfo)
|
||||||
iter != infoRefusalDialogue.mInfo.end(); ++iter)
|
if (testActor(info) && testPlayer(info) && testSelectStructs(info)
|
||||||
if (testActor(*iter) && testPlayer(*iter) && testSelectStructs(*iter)
|
&& testDisposition(info, invertDisposition))
|
||||||
&& testDisposition(*iter, invertDisposition))
|
|
||||||
{
|
{
|
||||||
infos.push_back(&*iter);
|
infos.emplace_back(&dialogue, &info);
|
||||||
if (!searchAll)
|
if (!searchAll)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef GAME_MWDIALOGUE_FILTER_H
|
#ifndef GAME_MWDIALOGUE_FILTER_H
|
||||||
#define GAME_MWDIALOGUE_FILTER_H
|
#define GAME_MWDIALOGUE_FILTER_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
@ -52,10 +53,12 @@ namespace MWDialogue
|
|||||||
const MWWorld::Ptr& actor, const ESM::RefId& factionId, int rank) const;
|
const MWWorld::Ptr& actor, const ESM::RefId& factionId, int rank) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Response = std::pair<const ESM::Dialogue*, const ESM::DialInfo*>;
|
||||||
|
|
||||||
Filter(const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
Filter(const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
||||||
|
|
||||||
std::vector<const ESM::DialInfo*> list(const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal,
|
std::vector<Response> list(const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll,
|
||||||
bool searchAll, bool invertDisposition = false) const;
|
bool invertDisposition = false) const;
|
||||||
///< List all infos that could be used on the given actor, using the current runtime state of the actor.
|
///< 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.
|
/// \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
|
///< Check if this INFO could potentially be said by the given actor, ignoring runtime state filters and
|
||||||
///< ignoring player filters.
|
///< 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.
|
///< Get a matching response for the requested dialogue.
|
||||||
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
|
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user