mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-21 11:39:44 +00:00
Detect service refusal in constant time
This commit is contained in:
parent
45c84a2426
commit
11f875d9c4
3 changed files with 40 additions and 52 deletions
|
@ -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…
Reference in a new issue