mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-01 11:11:31 +00:00
Deduplicate dialogue filter parsing
This commit is contained in:
parent
fb4edda45d
commit
a4625ea784
16 changed files with 1002 additions and 1414 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "labels.hpp"
|
#include "labels.hpp"
|
||||||
|
|
||||||
|
#include <components/esm3/dialoguecondition.hpp>
|
||||||
#include <components/esm3/loadalch.hpp>
|
#include <components/esm3/loadalch.hpp>
|
||||||
#include <components/esm3/loadbody.hpp>
|
#include <components/esm3/loadbody.hpp>
|
||||||
#include <components/esm3/loadcell.hpp>
|
#include <components/esm3/loadcell.hpp>
|
||||||
|
@ -572,13 +573,14 @@ std::string_view enchantTypeLabel(int idx)
|
||||||
|
|
||||||
std::string_view ruleFunction(int idx)
|
std::string_view ruleFunction(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx <= 72)
|
if (idx >= ESM::DialogueCondition::Function_FacReactionLowest
|
||||||
|
&& idx <= ESM::DialogueCondition::Function_PcWerewolfKills)
|
||||||
{
|
{
|
||||||
static constexpr std::string_view ruleFunctions[] = {
|
static constexpr std::string_view ruleFunctions[] = {
|
||||||
"Reaction Low",
|
"Lowest Faction Reaction",
|
||||||
"Reaction High",
|
"Highest Faction Reaction",
|
||||||
"Rank Requirement",
|
"Rank Requirement",
|
||||||
"NPC? Reputation",
|
"NPC Reputation",
|
||||||
"Health Percent",
|
"Health Percent",
|
||||||
"Player Reputation",
|
"Player Reputation",
|
||||||
"NPC Level",
|
"NPC Level",
|
||||||
|
@ -648,6 +650,7 @@ std::string_view ruleFunction(int idx)
|
||||||
"Flee",
|
"Flee",
|
||||||
"Should Attack",
|
"Should Attack",
|
||||||
"Werewolf",
|
"Werewolf",
|
||||||
|
"Werewolf Kills",
|
||||||
};
|
};
|
||||||
return ruleFunctions[idx];
|
return ruleFunctions[idx];
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,112 +57,82 @@ namespace
|
||||||
std::cout << " Cell Name: " << p.mCellName << std::endl;
|
std::cout << " Cell Name: " << p.mCellName << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ruleString(const ESM::DialInfo::SelectStruct& ss)
|
std::string ruleString(const ESM::DialogueCondition& ss)
|
||||||
{
|
{
|
||||||
std::string rule = ss.mSelectRule;
|
std::string_view type_str = "INVALID";
|
||||||
|
std::string_view func_str;
|
||||||
|
|
||||||
if (rule.length() < 5)
|
switch (ss.mFunction)
|
||||||
return "INVALID";
|
|
||||||
|
|
||||||
char type = rule[1];
|
|
||||||
char indicator = rule[2];
|
|
||||||
|
|
||||||
std::string type_str = "INVALID";
|
|
||||||
std::string func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3));
|
|
||||||
int func = Misc::StringUtils::toNumeric<int>(rule.substr(2, 2), 0);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
{
|
||||||
case '1':
|
case ESM::DialogueCondition::Function_Global:
|
||||||
type_str = "Function";
|
type_str = "Global";
|
||||||
func_str = std::string(ruleFunction(func));
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '2':
|
case ESM::DialogueCondition::Function_Local:
|
||||||
if (indicator == 's')
|
type_str = "Local";
|
||||||
type_str = "Global short";
|
func_str = ss.mVariable;
|
||||||
else if (indicator == 'l')
|
|
||||||
type_str = "Global long";
|
|
||||||
else if (indicator == 'f')
|
|
||||||
type_str = "Global float";
|
|
||||||
break;
|
break;
|
||||||
case '3':
|
case ESM::DialogueCondition::Function_Journal:
|
||||||
if (indicator == 's')
|
type_str = "Journal";
|
||||||
type_str = "Local short";
|
func_str = ss.mVariable;
|
||||||
else if (indicator == 'l')
|
|
||||||
type_str = "Local long";
|
|
||||||
else if (indicator == 'f')
|
|
||||||
type_str = "Local float";
|
|
||||||
break;
|
break;
|
||||||
case '4':
|
case ESM::DialogueCondition::Function_Item:
|
||||||
if (indicator == 'J')
|
type_str = "Item count";
|
||||||
type_str = "Journal";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '5':
|
case ESM::DialogueCondition::Function_Dead:
|
||||||
if (indicator == 'I')
|
type_str = "Dead";
|
||||||
type_str = "Item type";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '6':
|
case ESM::DialogueCondition::Function_NotId:
|
||||||
if (indicator == 'D')
|
type_str = "Not ID";
|
||||||
type_str = "NPC Dead";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '7':
|
case ESM::DialogueCondition::Function_NotFaction:
|
||||||
if (indicator == 'X')
|
type_str = "Not Faction";
|
||||||
type_str = "Not ID";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '8':
|
case ESM::DialogueCondition::Function_NotClass:
|
||||||
if (indicator == 'F')
|
type_str = "Not Class";
|
||||||
type_str = "Not Faction";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case '9':
|
case ESM::DialogueCondition::Function_NotRace:
|
||||||
if (indicator == 'C')
|
type_str = "Not Race";
|
||||||
type_str = "Not Class";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case ESM::DialogueCondition::Function_NotCell:
|
||||||
if (indicator == 'R')
|
type_str = "Not Cell";
|
||||||
type_str = "Not Race";
|
func_str = ss.mVariable;
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case ESM::DialogueCondition::Function_NotLocal:
|
||||||
if (indicator == 'L')
|
type_str = "Not Local";
|
||||||
type_str = "Not Cell";
|
func_str = ss.mVariable;
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
if (indicator == 's')
|
|
||||||
type_str = "Not Local";
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
type_str = "Function";
|
||||||
|
func_str = ruleFunction(ss.mFunction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the variable name to the function string if any.
|
std::string_view oper_str = "??";
|
||||||
if (type != '1')
|
switch (ss.mComparison)
|
||||||
func_str = rule.substr(5);
|
|
||||||
|
|
||||||
// In the previous switch, we assumed that the second char was X
|
|
||||||
// for all types not qual to one. If this wasn't true, go back to
|
|
||||||
// the error message.
|
|
||||||
if (type != '1' && rule[3] != 'X')
|
|
||||||
func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3));
|
|
||||||
|
|
||||||
char oper = rule[4];
|
|
||||||
std::string oper_str = "??";
|
|
||||||
switch (oper)
|
|
||||||
{
|
{
|
||||||
case '0':
|
case ESM::DialogueCondition::Comp_Eq:
|
||||||
oper_str = "==";
|
oper_str = "==";
|
||||||
break;
|
break;
|
||||||
case '1':
|
case ESM::DialogueCondition::Comp_Ne:
|
||||||
oper_str = "!=";
|
oper_str = "!=";
|
||||||
break;
|
break;
|
||||||
case '2':
|
case ESM::DialogueCondition::Comp_Gt:
|
||||||
oper_str = "> ";
|
oper_str = "> ";
|
||||||
break;
|
break;
|
||||||
case '3':
|
case ESM::DialogueCondition::Comp_Ge:
|
||||||
oper_str = ">=";
|
oper_str = ">=";
|
||||||
break;
|
break;
|
||||||
case '4':
|
case ESM::DialogueCondition::Comp_Ls:
|
||||||
oper_str = "< ";
|
oper_str = "< ";
|
||||||
break;
|
break;
|
||||||
case '5':
|
case ESM::DialogueCondition::Comp_Le:
|
||||||
oper_str = "<=";
|
oper_str = "<=";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -170,7 +140,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << ss.mValue;
|
std::visit([&](auto value) { stream << value; }, ss.mValue);
|
||||||
|
|
||||||
std::string result
|
std::string result
|
||||||
= Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str());
|
= Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str());
|
||||||
|
@ -842,7 +812,7 @@ namespace EsmTool
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << " Type: " << dialogTypeLabel(mData.mData.mType) << std::endl;
|
std::cout << " Type: " << dialogTypeLabel(mData.mData.mType) << std::endl;
|
||||||
|
|
||||||
for (const ESM::DialInfo::SelectStruct& rule : mData.mSelects)
|
for (const auto& rule : mData.mSelects)
|
||||||
std::cout << " Select Rule: " << ruleString(rule) << std::endl;
|
std::cout << " Select Rule: " << ruleString(rule) << std::endl;
|
||||||
|
|
||||||
if (!mData.mResultScript.empty())
|
if (!mData.mResultScript.empty())
|
||||||
|
|
|
@ -171,10 +171,9 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message
|
||||||
|
|
||||||
// Check info conditions
|
// Check info conditions
|
||||||
|
|
||||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator it = topicInfo.mSelects.begin();
|
for (const auto& select : topicInfo.mSelects)
|
||||||
it != topicInfo.mSelects.end(); ++it)
|
|
||||||
{
|
{
|
||||||
verifySelectStruct((*it), id, messages);
|
verifySelectStruct(select, id, messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,49 +307,15 @@ bool CSMTools::TopicInfoCheckStage::verifyItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
||||||
const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||||
{
|
{
|
||||||
CSMWorld::ConstInfoSelectWrapper infoCondition(select);
|
CSMWorld::ConstInfoSelectWrapper infoCondition(select);
|
||||||
|
|
||||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None)
|
if (select.mFunction == ESM::DialogueCondition::Function_None)
|
||||||
{
|
{
|
||||||
messages.add(id, "Invalid condition '" + infoCondition.toString() + "'", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Invalid condition '" + infoCondition.toString() + "'", "", CSMDoc::Message::Severity_Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!infoCondition.variantTypeIsValid())
|
|
||||||
{
|
|
||||||
std::ostringstream stream;
|
|
||||||
stream << "Value of condition '" << infoCondition.toString() << "' has invalid ";
|
|
||||||
|
|
||||||
switch (select.mValue.getType())
|
|
||||||
{
|
|
||||||
case ESM::VT_None:
|
|
||||||
stream << "None";
|
|
||||||
break;
|
|
||||||
case ESM::VT_Short:
|
|
||||||
stream << "Short";
|
|
||||||
break;
|
|
||||||
case ESM::VT_Int:
|
|
||||||
stream << "Int";
|
|
||||||
break;
|
|
||||||
case ESM::VT_Long:
|
|
||||||
stream << "Long";
|
|
||||||
break;
|
|
||||||
case ESM::VT_Float:
|
|
||||||
stream << "Float";
|
|
||||||
break;
|
|
||||||
case ESM::VT_String:
|
|
||||||
stream << "String";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream << "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
stream << " type";
|
|
||||||
|
|
||||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (infoCondition.conditionIsAlwaysTrue())
|
else if (infoCondition.conditionIsAlwaysTrue())
|
||||||
{
|
{
|
||||||
messages.add(
|
messages.add(
|
||||||
|
@ -365,48 +330,48 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id checks
|
// Id checks
|
||||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global
|
if (select.mFunction == ESM::DialogueCondition::Function_Global
|
||||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mGlobals, id, messages))
|
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mGlobals, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal
|
else if (select.mFunction == ESM::DialogueCondition::Function_Journal
|
||||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mJournals, id, messages))
|
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mJournals, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item
|
else if (select.mFunction == ESM::DialogueCondition::Function_Item
|
||||||
&& !verifyItem(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
&& !verifyItem(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead
|
else if (select.mFunction == ESM::DialogueCondition::Function_Dead
|
||||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId
|
else if (select.mFunction == ESM::DialogueCondition::Function_NotId
|
||||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction
|
else if (select.mFunction == ESM::DialogueCondition::Function_NotFaction
|
||||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mFactions, id, messages))
|
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mFactions, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass
|
else if (select.mFunction == ESM::DialogueCondition::Function_NotClass
|
||||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mClasses, id, messages))
|
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mClasses, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace
|
else if (select.mFunction == ESM::DialogueCondition::Function_NotRace
|
||||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mRaces, id, messages))
|
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mRaces, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell
|
else if (select.mFunction == ESM::DialogueCondition::Function_NotCell
|
||||||
&& !verifyCell(infoCondition.getVariableName(), id, messages))
|
&& !verifyCell(select.mVariable, id, messages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace CSMTools
|
||||||
const ESM::RefId& name, int rank, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
const ESM::RefId& name, int rank, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||||
bool verifyItem(const ESM::RefId& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
bool verifyItem(const ESM::RefId& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||||
bool verifySelectStruct(
|
bool verifySelectStruct(
|
||||||
const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||||
bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,133 +7,13 @@
|
||||||
|
|
||||||
#include <components/esm3/loadinfo.hpp>
|
#include <components/esm3/loadinfo.hpp>
|
||||||
|
|
||||||
namespace ESM
|
#include <QVariant>
|
||||||
{
|
|
||||||
class Variant;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
// ESM::DialInfo::SelectStruct.mSelectRule
|
|
||||||
// 012345...
|
|
||||||
// ^^^ ^^
|
|
||||||
// ||| ||
|
|
||||||
// ||| |+------------- condition variable string
|
|
||||||
// ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc
|
|
||||||
// ||+---------------- function index (encoded, where function == '1')
|
|
||||||
// |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc
|
|
||||||
// +------------------ unknown
|
|
||||||
//
|
|
||||||
|
|
||||||
// Wrapper for DialInfo::SelectStruct
|
|
||||||
class ConstInfoSelectWrapper
|
class ConstInfoSelectWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Order matters
|
|
||||||
enum FunctionName
|
|
||||||
{
|
|
||||||
Function_RankLow = 0,
|
|
||||||
Function_RankHigh,
|
|
||||||
Function_RankRequirement,
|
|
||||||
Function_Reputation,
|
|
||||||
Function_Health_Percent,
|
|
||||||
Function_PcReputation,
|
|
||||||
Function_PcLevel,
|
|
||||||
Function_PcHealthPercent,
|
|
||||||
Function_PcMagicka,
|
|
||||||
Function_PcFatigue,
|
|
||||||
Function_PcStrength,
|
|
||||||
Function_PcBlock,
|
|
||||||
Function_PcArmorer,
|
|
||||||
Function_PcMediumArmor,
|
|
||||||
Function_PcHeavyArmor,
|
|
||||||
Function_PcBluntWeapon,
|
|
||||||
Function_PcLongBlade,
|
|
||||||
Function_PcAxe,
|
|
||||||
Function_PcSpear,
|
|
||||||
Function_PcAthletics,
|
|
||||||
Function_PcEnchant,
|
|
||||||
Function_PcDestruction,
|
|
||||||
Function_PcAlteration,
|
|
||||||
Function_PcIllusion,
|
|
||||||
Function_PcConjuration,
|
|
||||||
Function_PcMysticism,
|
|
||||||
Function_PcRestoration,
|
|
||||||
Function_PcAlchemy,
|
|
||||||
Function_PcUnarmored,
|
|
||||||
Function_PcSecurity,
|
|
||||||
Function_PcSneak,
|
|
||||||
Function_PcAcrobatics,
|
|
||||||
Function_PcLightArmor,
|
|
||||||
Function_PcShortBlade,
|
|
||||||
Function_PcMarksman,
|
|
||||||
Function_PcMerchantile,
|
|
||||||
Function_PcSpeechcraft,
|
|
||||||
Function_PcHandToHand,
|
|
||||||
Function_PcGender,
|
|
||||||
Function_PcExpelled,
|
|
||||||
Function_PcCommonDisease,
|
|
||||||
Function_PcBlightDisease,
|
|
||||||
Function_PcClothingModifier,
|
|
||||||
Function_PcCrimeLevel,
|
|
||||||
Function_SameSex,
|
|
||||||
Function_SameRace,
|
|
||||||
Function_SameFaction,
|
|
||||||
Function_FactionRankDifference,
|
|
||||||
Function_Detected,
|
|
||||||
Function_Alarmed,
|
|
||||||
Function_Choice,
|
|
||||||
Function_PcIntelligence,
|
|
||||||
Function_PcWillpower,
|
|
||||||
Function_PcAgility,
|
|
||||||
Function_PcSpeed,
|
|
||||||
Function_PcEndurance,
|
|
||||||
Function_PcPersonality,
|
|
||||||
Function_PcLuck,
|
|
||||||
Function_PcCorpus,
|
|
||||||
Function_Weather,
|
|
||||||
Function_PcVampire,
|
|
||||||
Function_Level,
|
|
||||||
Function_Attacked,
|
|
||||||
Function_TalkedToPc,
|
|
||||||
Function_PcHealth,
|
|
||||||
Function_CreatureTarget,
|
|
||||||
Function_FriendHit,
|
|
||||||
Function_Fight,
|
|
||||||
Function_Hello,
|
|
||||||
Function_Alarm,
|
|
||||||
Function_Flee,
|
|
||||||
Function_ShouldAttack,
|
|
||||||
Function_Werewolf,
|
|
||||||
Function_PcWerewolfKills = 73,
|
|
||||||
|
|
||||||
Function_Global,
|
|
||||||
Function_Local,
|
|
||||||
Function_Journal,
|
|
||||||
Function_Item,
|
|
||||||
Function_Dead,
|
|
||||||
Function_NotId,
|
|
||||||
Function_NotFaction,
|
|
||||||
Function_NotClass,
|
|
||||||
Function_NotRace,
|
|
||||||
Function_NotCell,
|
|
||||||
Function_NotLocal,
|
|
||||||
|
|
||||||
Function_None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RelationType
|
|
||||||
{
|
|
||||||
Relation_Equal,
|
|
||||||
Relation_NotEqual,
|
|
||||||
Relation_Greater,
|
|
||||||
Relation_GreaterOrEqual,
|
|
||||||
Relation_Less,
|
|
||||||
Relation_LessOrEqual,
|
|
||||||
|
|
||||||
Relation_None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ComparisonType
|
enum ComparisonType
|
||||||
{
|
{
|
||||||
Comparison_Boolean,
|
Comparison_Boolean,
|
||||||
|
@ -143,25 +23,18 @@ namespace CSMWorld
|
||||||
Comparison_None
|
Comparison_None
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t RuleMinSize;
|
|
||||||
|
|
||||||
static const size_t FunctionPrefixOffset;
|
|
||||||
static const size_t FunctionIndexOffset;
|
|
||||||
static const size_t RelationIndexOffset;
|
|
||||||
static const size_t VarNameOffset;
|
|
||||||
|
|
||||||
static const char* FunctionEnumStrings[];
|
static const char* FunctionEnumStrings[];
|
||||||
static const char* RelationEnumStrings[];
|
static const char* RelationEnumStrings[];
|
||||||
static const char* ComparisonEnumStrings[];
|
static const char* ComparisonEnumStrings[];
|
||||||
|
|
||||||
static std::string convertToString(FunctionName name);
|
static std::string convertToString(ESM::DialogueCondition::Function name);
|
||||||
static std::string convertToString(RelationType type);
|
static std::string convertToString(ESM::DialogueCondition::Comparison type);
|
||||||
static std::string convertToString(ComparisonType type);
|
static std::string convertToString(ComparisonType type);
|
||||||
|
|
||||||
ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select);
|
ConstInfoSelectWrapper(const ESM::DialogueCondition& select);
|
||||||
|
|
||||||
FunctionName getFunctionName() const;
|
ESM::DialogueCondition::Function getFunctionName() const;
|
||||||
RelationType getRelationType() const;
|
ESM::DialogueCondition::Comparison getRelationType() const;
|
||||||
ComparisonType getComparisonType() const;
|
ComparisonType getComparisonType() const;
|
||||||
|
|
||||||
bool hasVariable() const;
|
bool hasVariable() const;
|
||||||
|
@ -169,17 +42,12 @@ namespace CSMWorld
|
||||||
|
|
||||||
bool conditionIsAlwaysTrue() const;
|
bool conditionIsAlwaysTrue() const;
|
||||||
bool conditionIsNeverTrue() const;
|
bool conditionIsNeverTrue() const;
|
||||||
bool variantTypeIsValid() const;
|
|
||||||
|
|
||||||
const ESM::Variant& getVariant() const;
|
QVariant getValue() const;
|
||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void readRule();
|
|
||||||
void readFunctionName();
|
|
||||||
void readRelationType();
|
|
||||||
void readVariableName();
|
|
||||||
void updateHasVariable();
|
void updateHasVariable();
|
||||||
void updateComparisonType();
|
void updateComparisonType();
|
||||||
|
|
||||||
|
@ -207,38 +75,29 @@ namespace CSMWorld
|
||||||
template <typename Type1, typename Type2>
|
template <typename Type1, typename Type2>
|
||||||
bool conditionIsNeverTrue(std::pair<Type1, Type1> conditionRange, std::pair<Type2, Type2> validRange) const;
|
bool conditionIsNeverTrue(std::pair<Type1, Type1> conditionRange, std::pair<Type2, Type2> validRange) const;
|
||||||
|
|
||||||
FunctionName mFunctionName;
|
|
||||||
RelationType mRelationType;
|
|
||||||
ComparisonType mComparisonType;
|
ComparisonType mComparisonType;
|
||||||
|
|
||||||
bool mHasVariable;
|
bool mHasVariable;
|
||||||
std::string mVariableName;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ESM::DialInfo::SelectStruct& mConstSelect;
|
const ESM::DialogueCondition& mConstSelect;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrapper for DialInfo::SelectStruct that can modify the wrapped select struct
|
// Wrapper for DialogueCondition that can modify the wrapped select struct
|
||||||
class InfoSelectWrapper : public ConstInfoSelectWrapper
|
class InfoSelectWrapper : public ConstInfoSelectWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InfoSelectWrapper(ESM::DialInfo::SelectStruct& select);
|
InfoSelectWrapper(ESM::DialogueCondition& select);
|
||||||
|
|
||||||
// Wrapped SelectStruct will not be modified until update() is called
|
// Wrapped SelectStruct will not be modified until update() is called
|
||||||
void setFunctionName(FunctionName name);
|
void setFunctionName(ESM::DialogueCondition::Function name);
|
||||||
void setRelationType(RelationType type);
|
void setRelationType(ESM::DialogueCondition::Comparison type);
|
||||||
void setVariableName(const std::string& name);
|
void setVariableName(const std::string& name);
|
||||||
|
void setValue(int value);
|
||||||
// Modified wrapped SelectStruct
|
void setValue(float value);
|
||||||
void update();
|
|
||||||
|
|
||||||
// This sets properties based on the function name to its defaults and updates the wrapped object
|
|
||||||
void setDefaults();
|
|
||||||
|
|
||||||
ESM::Variant& getVariant();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ESM::DialInfo::SelectStruct& mSelect;
|
ESM::DialogueCondition& mSelect;
|
||||||
|
|
||||||
void writeRule();
|
void writeRule();
|
||||||
};
|
};
|
||||||
|
|
|
@ -538,13 +538,11 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
Info info = record.get();
|
Info info = record.get();
|
||||||
|
|
||||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
auto& conditions = info.mSelects;
|
||||||
|
|
||||||
// default row
|
// default row
|
||||||
ESM::DialInfo::SelectStruct condStruct;
|
ESM::DialogueCondition condStruct;
|
||||||
condStruct.mSelectRule = "01000";
|
condStruct.mIndex = conditions.size();
|
||||||
condStruct.mValue = ESM::Variant();
|
|
||||||
condStruct.mValue.setType(ESM::VT_Int);
|
|
||||||
|
|
||||||
conditions.insert(conditions.begin() + position, condStruct);
|
conditions.insert(conditions.begin() + position, condStruct);
|
||||||
|
|
||||||
|
@ -555,7 +553,7 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
Info info = record.get();
|
Info info = record.get();
|
||||||
|
|
||||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
auto& conditions = info.mSelects;
|
||||||
|
|
||||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(conditions.size()))
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(conditions.size()))
|
||||||
throw std::runtime_error("index out of range");
|
throw std::runtime_error("index out of range");
|
||||||
|
@ -569,8 +567,8 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
Info info = record.get();
|
Info info = record.get();
|
||||||
|
|
||||||
info.mSelects = static_cast<const NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>&>(nestedTable)
|
info.mSelects
|
||||||
.mNestedTable;
|
= static_cast<const NestedTableWrapper<std::vector<ESM::DialogueCondition>>&>(nestedTable).mNestedTable;
|
||||||
|
|
||||||
record.setModified(info);
|
record.setModified(info);
|
||||||
}
|
}
|
||||||
|
@ -578,14 +576,14 @@ namespace CSMWorld
|
||||||
NestedTableWrapperBase* InfoConditionAdapter::table(const Record<Info>& record) const
|
NestedTableWrapperBase* InfoConditionAdapter::table(const Record<Info>& record) const
|
||||||
{
|
{
|
||||||
// deleted by dtor of NestedTableStoring
|
// deleted by dtor of NestedTableStoring
|
||||||
return new NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>(record.get().mSelects);
|
return new NestedTableWrapper<std::vector<ESM::DialogueCondition>>(record.get().mSelects);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant InfoConditionAdapter::getData(const Record<Info>& record, int subRowIndex, int subColIndex) const
|
QVariant InfoConditionAdapter::getData(const Record<Info>& record, int subRowIndex, int subColIndex) const
|
||||||
{
|
{
|
||||||
Info info = record.get();
|
Info info = record.get();
|
||||||
|
|
||||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
auto& conditions = info.mSelects;
|
||||||
|
|
||||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
||||||
throw std::runtime_error("index out of range");
|
throw std::runtime_error("index out of range");
|
||||||
|
@ -611,19 +609,7 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
switch (infoSelectWrapper.getVariant().getType())
|
return infoSelectWrapper.getValue();
|
||||||
{
|
|
||||||
case ESM::VT_Int:
|
|
||||||
{
|
|
||||||
return infoSelectWrapper.getVariant().getInteger();
|
|
||||||
}
|
|
||||||
case ESM::VT_Float:
|
|
||||||
{
|
|
||||||
return infoSelectWrapper.getVariant().getFloat();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Info condition subcolumn index out of range");
|
throw std::runtime_error("Info condition subcolumn index out of range");
|
||||||
|
@ -635,7 +621,7 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
Info info = record.get();
|
Info info = record.get();
|
||||||
|
|
||||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
auto& conditions = info.mSelects;
|
||||||
|
|
||||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
||||||
throw std::runtime_error("index out of range");
|
throw std::runtime_error("index out of range");
|
||||||
|
@ -647,27 +633,17 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
case 0: // Function
|
case 0: // Function
|
||||||
{
|
{
|
||||||
infoSelectWrapper.setFunctionName(static_cast<ConstInfoSelectWrapper::FunctionName>(value.toInt()));
|
infoSelectWrapper.setFunctionName(static_cast<ESM::DialogueCondition::Function>(value.toInt()));
|
||||||
|
|
||||||
if (infoSelectWrapper.getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric
|
|
||||||
&& infoSelectWrapper.getVariant().getType() != ESM::VT_Int)
|
|
||||||
{
|
|
||||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
|
||||||
}
|
|
||||||
|
|
||||||
infoSelectWrapper.update();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: // Variable
|
case 1: // Variable
|
||||||
{
|
{
|
||||||
infoSelectWrapper.setVariableName(value.toString().toUtf8().constData());
|
infoSelectWrapper.setVariableName(value.toString().toUtf8().constData());
|
||||||
infoSelectWrapper.update();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: // Relation
|
case 2: // Relation
|
||||||
{
|
{
|
||||||
infoSelectWrapper.setRelationType(static_cast<ConstInfoSelectWrapper::RelationType>(value.toInt()));
|
infoSelectWrapper.setRelationType(static_cast<ESM::DialogueCondition::Comparison>(value.toInt()));
|
||||||
infoSelectWrapper.update();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: // Value
|
case 3: // Value
|
||||||
|
@ -679,13 +655,11 @@ namespace CSMWorld
|
||||||
// QVariant seems to have issues converting 0
|
// QVariant seems to have issues converting 0
|
||||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||||
{
|
{
|
||||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
infoSelectWrapper.setValue(value.toInt());
|
||||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
|
||||||
}
|
}
|
||||||
else if (value.toFloat(&conversionResult) && conversionResult)
|
else if (value.toFloat(&conversionResult) && conversionResult)
|
||||||
{
|
{
|
||||||
infoSelectWrapper.getVariant().setType(ESM::VT_Float);
|
infoSelectWrapper.setValue(value.toFloat());
|
||||||
infoSelectWrapper.getVariant().setFloat(value.toFloat());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -694,8 +668,7 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||||
{
|
{
|
||||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
infoSelectWrapper.setValue(value.toInt());
|
||||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,41 +46,41 @@ QWidget* CSVWorld::IdCompletionDelegate::createEditor(QWidget* parent, const QSt
|
||||||
|
|
||||||
switch (conditionFunction)
|
switch (conditionFunction)
|
||||||
{
|
{
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_Global:
|
case ESM::DialogueCondition::Function_Global:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_GlobalVariable);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_GlobalVariable);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_Journal:
|
case ESM::DialogueCondition::Function_Journal:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Journal);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Journal);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_Item:
|
case ESM::DialogueCondition::Function_Item:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_Dead:
|
case ESM::DialogueCondition::Function_Dead:
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotId:
|
case ESM::DialogueCondition::Function_NotId:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotFaction:
|
case ESM::DialogueCondition::Function_NotFaction:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Faction);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Faction);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotClass:
|
case ESM::DialogueCondition::Function_NotClass:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Class);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Class);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotRace:
|
case ESM::DialogueCondition::Function_NotRace:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Race);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Race);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotCell:
|
case ESM::DialogueCondition::Function_NotCell:
|
||||||
{
|
{
|
||||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Cell);
|
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Cell);
|
||||||
}
|
}
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_Local:
|
case ESM::DialogueCondition::Function_Local:
|
||||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotLocal:
|
case ESM::DialogueCondition::Function_NotLocal:
|
||||||
{
|
{
|
||||||
return new CSVWidget::DropLineEdit(display, parent);
|
return new CSVWidget::DropLineEdit(display, parent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,15 @@ namespace
|
||||||
bool matchesStaticFilters(const MWDialogue::SelectWrapper& select, const MWWorld::Ptr& actor)
|
bool matchesStaticFilters(const MWDialogue::SelectWrapper& select, const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
const ESM::RefId selectId = select.getId();
|
const ESM::RefId selectId = select.getId();
|
||||||
if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotId)
|
if (select.getFunction() == ESM::DialogueCondition::Function_NotId)
|
||||||
return actor.getCellRef().getRefId() != selectId;
|
return actor.getCellRef().getRefId() != selectId;
|
||||||
if (actor.getClass().isNpc())
|
if (actor.getClass().isNpc())
|
||||||
{
|
{
|
||||||
if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotFaction)
|
if (select.getFunction() == ESM::DialogueCondition::Function_NotFaction)
|
||||||
return actor.getClass().getPrimaryFaction(actor) != selectId;
|
return actor.getClass().getPrimaryFaction(actor) != selectId;
|
||||||
else if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotClass)
|
else if (select.getFunction() == ESM::DialogueCondition::Function_NotClass)
|
||||||
return actor.get<ESM::NPC>()->mBase->mClass != selectId;
|
return actor.get<ESM::NPC>()->mBase->mClass != selectId;
|
||||||
else if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotRace)
|
else if (select.getFunction() == ESM::DialogueCondition::Function_NotRace)
|
||||||
return actor.get<ESM::NPC>()->mBase->mRace != selectId;
|
return actor.get<ESM::NPC>()->mBase->mRace != selectId;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -47,7 +47,7 @@ namespace
|
||||||
|
|
||||||
bool matchesStaticFilters(const ESM::DialInfo& info, const MWWorld::Ptr& actor)
|
bool matchesStaticFilters(const ESM::DialInfo& info, const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
for (const ESM::DialInfo::SelectStruct& select : info.mSelects)
|
for (const auto& select : info.mSelects)
|
||||||
{
|
{
|
||||||
MWDialogue::SelectWrapper wrapper = select;
|
MWDialogue::SelectWrapper wrapper = select;
|
||||||
if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Boolean)
|
if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Boolean)
|
||||||
|
@ -62,7 +62,7 @@ namespace
|
||||||
}
|
}
|
||||||
else if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Numeric)
|
else if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Numeric)
|
||||||
{
|
{
|
||||||
if (wrapper.getFunction() == MWDialogue::SelectWrapper::Function_Local)
|
if (wrapper.getFunction() == ESM::DialogueCondition::Function_Local)
|
||||||
{
|
{
|
||||||
const ESM::RefId& scriptName = actor.getClass().getScript(actor);
|
const ESM::RefId& scriptName = actor.getClass().getScript(actor);
|
||||||
if (scriptName.empty())
|
if (scriptName.empty())
|
||||||
|
@ -207,9 +207,8 @@ bool MWDialogue::Filter::testPlayer(const ESM::DialInfo& info) const
|
||||||
|
|
||||||
bool MWDialogue::Filter::testSelectStructs(const ESM::DialInfo& info) const
|
bool MWDialogue::Filter::testSelectStructs(const ESM::DialInfo& info) const
|
||||||
{
|
{
|
||||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter(info.mSelects.begin());
|
for (const auto& select : info.mSelects)
|
||||||
iter != info.mSelects.end(); ++iter)
|
if (!testSelectStruct(select))
|
||||||
if (!testSelectStruct(*iter))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -270,11 +269,11 @@ bool MWDialogue::Filter::testSelectStruct(const SelectWrapper& select) const
|
||||||
// If the actor is a creature, we pass all conditions only applicable to NPCs.
|
// If the actor is a creature, we pass all conditions only applicable to NPCs.
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (select.getFunction() == SelectWrapper::Function_Choice && mChoice == -1)
|
if (select.getFunction() == ESM::DialogueCondition::Function_Choice && mChoice == -1)
|
||||||
// If not currently in a choice, we reject all conditions that test against choices.
|
// If not currently in a choice, we reject all conditions that test against choices.
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (select.getFunction() == SelectWrapper::Function_Weather
|
if (select.getFunction() == ESM::DialogueCondition::Function_Weather
|
||||||
&& !(MWBase::Environment::get().getWorld()->isCellExterior()
|
&& !(MWBase::Environment::get().getWorld()->isCellExterior()
|
||||||
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior()))
|
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior()))
|
||||||
// Reject weather conditions in interior cells
|
// Reject weather conditions in interior cells
|
||||||
|
@ -305,29 +304,31 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co
|
||||||
{
|
{
|
||||||
switch (select.getFunction())
|
switch (select.getFunction())
|
||||||
{
|
{
|
||||||
case SelectWrapper::Function_Global:
|
case ESM::DialogueCondition::Function_Global:
|
||||||
|
|
||||||
// internally all globals are float :(
|
// internally all globals are float :(
|
||||||
return select.selectCompare(MWBase::Environment::get().getWorld()->getGlobalFloat(select.getName()));
|
return select.selectCompare(MWBase::Environment::get().getWorld()->getGlobalFloat(select.getName()));
|
||||||
|
|
||||||
case SelectWrapper::Function_Local:
|
case ESM::DialogueCondition::Function_Local:
|
||||||
{
|
{
|
||||||
return testFunctionLocal(select);
|
return testFunctionLocal(select);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_NotLocal:
|
case ESM::DialogueCondition::Function_NotLocal:
|
||||||
{
|
{
|
||||||
return !testFunctionLocal(select);
|
return !testFunctionLocal(select);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_PcHealthPercent:
|
case ESM::DialogueCondition::Function_PcHealthPercent:
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
return select.selectCompare(
|
return select.selectCompare(
|
||||||
static_cast<int>(player.getClass().getCreatureStats(player).getHealth().getRatio() * 100));
|
static_cast<int>(player.getClass().getCreatureStats(player).getHealth().getRatio() * 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_PcDynamicStat:
|
case ESM::DialogueCondition::Function_PcMagicka:
|
||||||
|
case ESM::DialogueCondition::Function_PcFatigue:
|
||||||
|
case ESM::DialogueCondition::Function_PcHealth:
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
|
||||||
|
@ -336,7 +337,7 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co
|
||||||
return select.selectCompare(value);
|
return select.selectCompare(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_HealthPercent:
|
case ESM::DialogueCondition::Function_Health_Percent:
|
||||||
{
|
{
|
||||||
return select.selectCompare(
|
return select.selectCompare(
|
||||||
static_cast<int>(mActor.getClass().getCreatureStats(mActor).getHealth().getRatio() * 100));
|
static_cast<int>(mActor.getClass().getCreatureStats(mActor).getHealth().getRatio() * 100));
|
||||||
|
@ -354,26 +355,29 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
|
|
||||||
switch (select.getFunction())
|
switch (select.getFunction())
|
||||||
{
|
{
|
||||||
case SelectWrapper::Function_Journal:
|
case ESM::DialogueCondition::Function_Journal:
|
||||||
|
|
||||||
return MWBase::Environment::get().getJournal()->getJournalIndex(select.getId());
|
return MWBase::Environment::get().getJournal()->getJournalIndex(select.getId());
|
||||||
|
|
||||||
case SelectWrapper::Function_Item:
|
case ESM::DialogueCondition::Function_Item:
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
||||||
|
|
||||||
return store.count(select.getId());
|
return store.count(select.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_Dead:
|
case ESM::DialogueCondition::Function_Dead:
|
||||||
|
|
||||||
return MWBase::Environment::get().getMechanicsManager()->countDeaths(select.getId());
|
return MWBase::Environment::get().getMechanicsManager()->countDeaths(select.getId());
|
||||||
|
|
||||||
case SelectWrapper::Function_Choice:
|
case ESM::DialogueCondition::Function_Choice:
|
||||||
|
|
||||||
return mChoice;
|
return mChoice;
|
||||||
|
|
||||||
case SelectWrapper::Function_AiSetting:
|
case ESM::DialogueCondition::Function_Fight:
|
||||||
|
case ESM::DialogueCondition::Function_Hello:
|
||||||
|
case ESM::DialogueCondition::Function_Alarm:
|
||||||
|
case ESM::DialogueCondition::Function_Flee:
|
||||||
{
|
{
|
||||||
int argument = select.getArgument();
|
int argument = select.getArgument();
|
||||||
if (argument < 0 || argument > 3)
|
if (argument < 0 || argument > 3)
|
||||||
|
@ -386,32 +390,65 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
.getAiSetting(static_cast<MWMechanics::AiSetting>(argument))
|
.getAiSetting(static_cast<MWMechanics::AiSetting>(argument))
|
||||||
.getModified(false);
|
.getModified(false);
|
||||||
}
|
}
|
||||||
case SelectWrapper::Function_PcAttribute:
|
case ESM::DialogueCondition::Function_PcStrength:
|
||||||
|
case ESM::DialogueCondition::Function_PcIntelligence:
|
||||||
|
case ESM::DialogueCondition::Function_PcWillpower:
|
||||||
|
case ESM::DialogueCondition::Function_PcAgility:
|
||||||
|
case ESM::DialogueCondition::Function_PcSpeed:
|
||||||
|
case ESM::DialogueCondition::Function_PcEndurance:
|
||||||
|
case ESM::DialogueCondition::Function_PcPersonality:
|
||||||
|
case ESM::DialogueCondition::Function_PcLuck:
|
||||||
{
|
{
|
||||||
ESM::RefId attribute = ESM::Attribute::indexToRefId(select.getArgument());
|
ESM::RefId attribute = ESM::Attribute::indexToRefId(select.getArgument());
|
||||||
return player.getClass().getCreatureStats(player).getAttribute(attribute).getModified();
|
return player.getClass().getCreatureStats(player).getAttribute(attribute).getModified();
|
||||||
}
|
}
|
||||||
case SelectWrapper::Function_PcSkill:
|
case ESM::DialogueCondition::Function_PcBlock:
|
||||||
|
case ESM::DialogueCondition::Function_PcArmorer:
|
||||||
|
case ESM::DialogueCondition::Function_PcMediumArmor:
|
||||||
|
case ESM::DialogueCondition::Function_PcHeavyArmor:
|
||||||
|
case ESM::DialogueCondition::Function_PcBluntWeapon:
|
||||||
|
case ESM::DialogueCondition::Function_PcLongBlade:
|
||||||
|
case ESM::DialogueCondition::Function_PcAxe:
|
||||||
|
case ESM::DialogueCondition::Function_PcSpear:
|
||||||
|
case ESM::DialogueCondition::Function_PcAthletics:
|
||||||
|
case ESM::DialogueCondition::Function_PcEnchant:
|
||||||
|
case ESM::DialogueCondition::Function_PcDestruction:
|
||||||
|
case ESM::DialogueCondition::Function_PcAlteration:
|
||||||
|
case ESM::DialogueCondition::Function_PcIllusion:
|
||||||
|
case ESM::DialogueCondition::Function_PcConjuration:
|
||||||
|
case ESM::DialogueCondition::Function_PcMysticism:
|
||||||
|
case ESM::DialogueCondition::Function_PcRestoration:
|
||||||
|
case ESM::DialogueCondition::Function_PcAlchemy:
|
||||||
|
case ESM::DialogueCondition::Function_PcUnarmored:
|
||||||
|
case ESM::DialogueCondition::Function_PcSecurity:
|
||||||
|
case ESM::DialogueCondition::Function_PcSneak:
|
||||||
|
case ESM::DialogueCondition::Function_PcAcrobatics:
|
||||||
|
case ESM::DialogueCondition::Function_PcLightArmor:
|
||||||
|
case ESM::DialogueCondition::Function_PcShortBlade:
|
||||||
|
case ESM::DialogueCondition::Function_PcMarksman:
|
||||||
|
case ESM::DialogueCondition::Function_PcMerchantile:
|
||||||
|
case ESM::DialogueCondition::Function_PcSpeechcraft:
|
||||||
|
case ESM::DialogueCondition::Function_PcHandToHand:
|
||||||
{
|
{
|
||||||
ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument());
|
ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument());
|
||||||
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(skill).getModified());
|
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(skill).getModified());
|
||||||
}
|
}
|
||||||
case SelectWrapper::Function_FriendlyHit:
|
case ESM::DialogueCondition::Function_FriendHit:
|
||||||
{
|
{
|
||||||
int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits();
|
int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits();
|
||||||
|
|
||||||
return hits > 4 ? 4 : hits;
|
return hits > 4 ? 4 : hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_PcLevel:
|
case ESM::DialogueCondition::Function_PcLevel:
|
||||||
|
|
||||||
return player.getClass().getCreatureStats(player).getLevel();
|
return player.getClass().getCreatureStats(player).getLevel();
|
||||||
|
|
||||||
case SelectWrapper::Function_PcGender:
|
case ESM::DialogueCondition::Function_PcGender:
|
||||||
|
|
||||||
return player.get<ESM::NPC>()->mBase->isMale() ? 0 : 1;
|
return player.get<ESM::NPC>()->mBase->isMale() ? 0 : 1;
|
||||||
|
|
||||||
case SelectWrapper::Function_PcClothingModifier:
|
case ESM::DialogueCondition::Function_PcClothingModifier:
|
||||||
{
|
{
|
||||||
const MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
const MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||||
|
|
||||||
|
@ -428,11 +465,11 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_PcCrimeLevel:
|
case ESM::DialogueCondition::Function_PcCrimeLevel:
|
||||||
|
|
||||||
return player.getClass().getNpcStats(player).getBounty();
|
return player.getClass().getNpcStats(player).getBounty();
|
||||||
|
|
||||||
case SelectWrapper::Function_RankRequirement:
|
case ESM::DialogueCondition::Function_RankRequirement:
|
||||||
{
|
{
|
||||||
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
||||||
if (faction.empty())
|
if (faction.empty())
|
||||||
|
@ -454,23 +491,23 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_Level:
|
case ESM::DialogueCondition::Function_Level:
|
||||||
|
|
||||||
return mActor.getClass().getCreatureStats(mActor).getLevel();
|
return mActor.getClass().getCreatureStats(mActor).getLevel();
|
||||||
|
|
||||||
case SelectWrapper::Function_PCReputation:
|
case ESM::DialogueCondition::Function_PcReputation:
|
||||||
|
|
||||||
return player.getClass().getNpcStats(player).getReputation();
|
return player.getClass().getNpcStats(player).getReputation();
|
||||||
|
|
||||||
case SelectWrapper::Function_Weather:
|
case ESM::DialogueCondition::Function_Weather:
|
||||||
|
|
||||||
return MWBase::Environment::get().getWorld()->getCurrentWeather();
|
return MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||||
|
|
||||||
case SelectWrapper::Function_Reputation:
|
case ESM::DialogueCondition::Function_Reputation:
|
||||||
|
|
||||||
return mActor.getClass().getNpcStats(mActor).getReputation();
|
return mActor.getClass().getNpcStats(mActor).getReputation();
|
||||||
|
|
||||||
case SelectWrapper::Function_FactionRankDiff:
|
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||||
{
|
{
|
||||||
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
||||||
|
|
||||||
|
@ -482,14 +519,14 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
return rank - npcRank;
|
return rank - npcRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_WerewolfKills:
|
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||||
|
|
||||||
return player.getClass().getNpcStats(player).getWerewolfKills();
|
return player.getClass().getNpcStats(player).getWerewolfKills();
|
||||||
|
|
||||||
case SelectWrapper::Function_RankLow:
|
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||||
case SelectWrapper::Function_RankHigh:
|
case ESM::DialogueCondition::Function_FacReactionHighest:
|
||||||
{
|
{
|
||||||
bool low = select.getFunction() == SelectWrapper::Function_RankLow;
|
bool low = select.getFunction() == ESM::DialogueCondition::Function_FacReactionLowest;
|
||||||
|
|
||||||
const ESM::RefId& factionId = mActor.getClass().getPrimaryFaction(mActor);
|
const ESM::RefId& factionId = mActor.getClass().getPrimaryFaction(mActor);
|
||||||
|
|
||||||
|
@ -512,7 +549,7 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_CreatureTargetted:
|
case ESM::DialogueCondition::Function_CreatureTarget:
|
||||||
|
|
||||||
{
|
{
|
||||||
MWWorld::Ptr target;
|
MWWorld::Ptr target;
|
||||||
|
@ -539,53 +576,49 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||||
|
|
||||||
switch (select.getFunction())
|
switch (select.getFunction())
|
||||||
{
|
{
|
||||||
case SelectWrapper::Function_False:
|
case ESM::DialogueCondition::Function_NotId:
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case SelectWrapper::Function_NotId:
|
|
||||||
|
|
||||||
return mActor.getCellRef().getRefId() != select.getId();
|
return mActor.getCellRef().getRefId() != select.getId();
|
||||||
|
|
||||||
case SelectWrapper::Function_NotFaction:
|
case ESM::DialogueCondition::Function_NotFaction:
|
||||||
|
|
||||||
return mActor.getClass().getPrimaryFaction(mActor) != select.getId();
|
return mActor.getClass().getPrimaryFaction(mActor) != select.getId();
|
||||||
|
|
||||||
case SelectWrapper::Function_NotClass:
|
case ESM::DialogueCondition::Function_NotClass:
|
||||||
|
|
||||||
return mActor.get<ESM::NPC>()->mBase->mClass != select.getId();
|
return mActor.get<ESM::NPC>()->mBase->mClass != select.getId();
|
||||||
|
|
||||||
case SelectWrapper::Function_NotRace:
|
case ESM::DialogueCondition::Function_NotRace:
|
||||||
|
|
||||||
return mActor.get<ESM::NPC>()->mBase->mRace != select.getId();
|
return mActor.get<ESM::NPC>()->mBase->mRace != select.getId();
|
||||||
|
|
||||||
case SelectWrapper::Function_NotCell:
|
case ESM::DialogueCondition::Function_NotCell:
|
||||||
{
|
{
|
||||||
std::string_view actorCell = MWBase::Environment::get().getWorld()->getCellName(mActor.getCell());
|
std::string_view actorCell = MWBase::Environment::get().getWorld()->getCellName(mActor.getCell());
|
||||||
return !Misc::StringUtils::ciStartsWith(actorCell, select.getCellName());
|
return !Misc::StringUtils::ciStartsWith(actorCell, select.getCellName());
|
||||||
}
|
}
|
||||||
case SelectWrapper::Function_SameGender:
|
case ESM::DialogueCondition::Function_SameSex:
|
||||||
|
|
||||||
return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)
|
return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)
|
||||||
== (mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female);
|
== (mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female);
|
||||||
|
|
||||||
case SelectWrapper::Function_SameRace:
|
case ESM::DialogueCondition::Function_SameRace:
|
||||||
|
|
||||||
return mActor.get<ESM::NPC>()->mBase->mRace == player.get<ESM::NPC>()->mBase->mRace;
|
return mActor.get<ESM::NPC>()->mBase->mRace == player.get<ESM::NPC>()->mBase->mRace;
|
||||||
|
|
||||||
case SelectWrapper::Function_SameFaction:
|
case ESM::DialogueCondition::Function_SameFaction:
|
||||||
|
|
||||||
return player.getClass().getNpcStats(player).isInFaction(mActor.getClass().getPrimaryFaction(mActor));
|
return player.getClass().getNpcStats(player).isInFaction(mActor.getClass().getPrimaryFaction(mActor));
|
||||||
|
|
||||||
case SelectWrapper::Function_PcCommonDisease:
|
case ESM::DialogueCondition::Function_PcCommonDisease:
|
||||||
|
|
||||||
return player.getClass().getCreatureStats(player).hasCommonDisease();
|
return player.getClass().getCreatureStats(player).hasCommonDisease();
|
||||||
|
|
||||||
case SelectWrapper::Function_PcBlightDisease:
|
case ESM::DialogueCondition::Function_PcBlightDisease:
|
||||||
|
|
||||||
return player.getClass().getCreatureStats(player).hasBlightDisease();
|
return player.getClass().getCreatureStats(player).hasBlightDisease();
|
||||||
|
|
||||||
case SelectWrapper::Function_PcCorprus:
|
case ESM::DialogueCondition::Function_PcCorpus:
|
||||||
|
|
||||||
return player.getClass()
|
return player.getClass()
|
||||||
.getCreatureStats(player)
|
.getCreatureStats(player)
|
||||||
|
@ -594,7 +627,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||||
.getMagnitude()
|
.getMagnitude()
|
||||||
!= 0;
|
!= 0;
|
||||||
|
|
||||||
case SelectWrapper::Function_PcExpelled:
|
case ESM::DialogueCondition::Function_PcExpelled:
|
||||||
{
|
{
|
||||||
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
||||||
|
|
||||||
|
@ -604,7 +637,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||||
return player.getClass().getNpcStats(player).getExpelled(faction);
|
return player.getClass().getNpcStats(player).getExpelled(faction);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SelectWrapper::Function_PcVampire:
|
case ESM::DialogueCondition::Function_PcVampire:
|
||||||
|
|
||||||
return player.getClass()
|
return player.getClass()
|
||||||
.getCreatureStats(player)
|
.getCreatureStats(player)
|
||||||
|
@ -613,27 +646,27 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||||
.getMagnitude()
|
.getMagnitude()
|
||||||
> 0;
|
> 0;
|
||||||
|
|
||||||
case SelectWrapper::Function_TalkedToPc:
|
case ESM::DialogueCondition::Function_TalkedToPc:
|
||||||
|
|
||||||
return mTalkedToPlayer;
|
return mTalkedToPlayer;
|
||||||
|
|
||||||
case SelectWrapper::Function_Alarmed:
|
case ESM::DialogueCondition::Function_Alarmed:
|
||||||
|
|
||||||
return mActor.getClass().getCreatureStats(mActor).isAlarmed();
|
return mActor.getClass().getCreatureStats(mActor).isAlarmed();
|
||||||
|
|
||||||
case SelectWrapper::Function_Detected:
|
case ESM::DialogueCondition::Function_Detected:
|
||||||
|
|
||||||
return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor);
|
return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor);
|
||||||
|
|
||||||
case SelectWrapper::Function_Attacked:
|
case ESM::DialogueCondition::Function_Attacked:
|
||||||
|
|
||||||
return mActor.getClass().getCreatureStats(mActor).getAttacked();
|
return mActor.getClass().getCreatureStats(mActor).getAttacked();
|
||||||
|
|
||||||
case SelectWrapper::Function_ShouldAttack:
|
case ESM::DialogueCondition::Function_ShouldAttack:
|
||||||
|
|
||||||
return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWMechanics::getPlayer());
|
return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWMechanics::getPlayer());
|
||||||
|
|
||||||
case SelectWrapper::Function_Werewolf:
|
case ESM::DialogueCondition::Function_Werewolf:
|
||||||
|
|
||||||
return mActor.getClass().getNpcStats(mActor).isWerewolf();
|
return mActor.getClass().getNpcStats(mActor).isWerewolf();
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,21 @@
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
bool selectCompareImp(char comp, T1 value1, T2 value2)
|
bool selectCompareImp(ESM::DialogueCondition::Comparison comp, T1 value1, T2 value2)
|
||||||
{
|
{
|
||||||
switch (comp)
|
switch (comp)
|
||||||
{
|
{
|
||||||
case '0':
|
case ESM::DialogueCondition::Comp_Eq:
|
||||||
return value1 == value2;
|
return value1 == value2;
|
||||||
case '1':
|
case ESM::DialogueCondition::Comp_Ne:
|
||||||
return value1 != value2;
|
return value1 != value2;
|
||||||
case '2':
|
case ESM::DialogueCondition::Comp_Gt:
|
||||||
return value1 > value2;
|
return value1 > value2;
|
||||||
case '3':
|
case ESM::DialogueCondition::Comp_Ge:
|
||||||
return value1 >= value2;
|
return value1 >= value2;
|
||||||
case '4':
|
case ESM::DialogueCondition::Comp_Ls:
|
||||||
return value1 < value2;
|
return value1 < value2;
|
||||||
case '5':
|
case ESM::DialogueCondition::Comp_Le:
|
||||||
return value1 <= value2;
|
return value1 <= value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,409 +32,242 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool selectCompareImp(const ESM::DialInfo::SelectStruct& select, T value1)
|
bool selectCompareImp(const ESM::DialogueCondition& select, T value1)
|
||||||
{
|
{
|
||||||
if (select.mValue.getType() == ESM::VT_Int)
|
return std::visit(
|
||||||
{
|
[&](auto value) { return selectCompareImp(select.mComparison, value1, value); }, select.mValue);
|
||||||
return selectCompareImp(select.mSelectRule[4], value1, select.mValue.getInteger());
|
|
||||||
}
|
|
||||||
else if (select.mValue.getType() == ESM::VT_Float)
|
|
||||||
{
|
|
||||||
return selectCompareImp(select.mSelectRule[4], value1, select.mValue.getFloat());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw std::runtime_error("unsupported variable type in dialogue info select");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const
|
MWDialogue::SelectWrapper::SelectWrapper(const ESM::DialogueCondition& select)
|
||||||
{
|
|
||||||
const int index = Misc::StringUtils::toNumeric<int>(mSelect.mSelectRule.substr(2, 2), 0);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return Function_RankLow;
|
|
||||||
case 1:
|
|
||||||
return Function_RankHigh;
|
|
||||||
case 2:
|
|
||||||
return Function_RankRequirement;
|
|
||||||
case 3:
|
|
||||||
return Function_Reputation;
|
|
||||||
case 4:
|
|
||||||
return Function_HealthPercent;
|
|
||||||
case 5:
|
|
||||||
return Function_PCReputation;
|
|
||||||
case 6:
|
|
||||||
return Function_PcLevel;
|
|
||||||
case 7:
|
|
||||||
return Function_PcHealthPercent;
|
|
||||||
case 8:
|
|
||||||
case 9:
|
|
||||||
return Function_PcDynamicStat;
|
|
||||||
case 10:
|
|
||||||
return Function_PcAttribute;
|
|
||||||
case 11:
|
|
||||||
case 12:
|
|
||||||
case 13:
|
|
||||||
case 14:
|
|
||||||
case 15:
|
|
||||||
case 16:
|
|
||||||
case 17:
|
|
||||||
case 18:
|
|
||||||
case 19:
|
|
||||||
case 20:
|
|
||||||
case 21:
|
|
||||||
case 22:
|
|
||||||
case 23:
|
|
||||||
case 24:
|
|
||||||
case 25:
|
|
||||||
case 26:
|
|
||||||
case 27:
|
|
||||||
case 28:
|
|
||||||
case 29:
|
|
||||||
case 30:
|
|
||||||
case 31:
|
|
||||||
case 32:
|
|
||||||
case 33:
|
|
||||||
case 34:
|
|
||||||
case 35:
|
|
||||||
case 36:
|
|
||||||
case 37:
|
|
||||||
return Function_PcSkill;
|
|
||||||
case 38:
|
|
||||||
return Function_PcGender;
|
|
||||||
case 39:
|
|
||||||
return Function_PcExpelled;
|
|
||||||
case 40:
|
|
||||||
return Function_PcCommonDisease;
|
|
||||||
case 41:
|
|
||||||
return Function_PcBlightDisease;
|
|
||||||
case 42:
|
|
||||||
return Function_PcClothingModifier;
|
|
||||||
case 43:
|
|
||||||
return Function_PcCrimeLevel;
|
|
||||||
case 44:
|
|
||||||
return Function_SameGender;
|
|
||||||
case 45:
|
|
||||||
return Function_SameRace;
|
|
||||||
case 46:
|
|
||||||
return Function_SameFaction;
|
|
||||||
case 47:
|
|
||||||
return Function_FactionRankDiff;
|
|
||||||
case 48:
|
|
||||||
return Function_Detected;
|
|
||||||
case 49:
|
|
||||||
return Function_Alarmed;
|
|
||||||
case 50:
|
|
||||||
return Function_Choice;
|
|
||||||
case 51:
|
|
||||||
case 52:
|
|
||||||
case 53:
|
|
||||||
case 54:
|
|
||||||
case 55:
|
|
||||||
case 56:
|
|
||||||
case 57:
|
|
||||||
return Function_PcAttribute;
|
|
||||||
case 58:
|
|
||||||
return Function_PcCorprus;
|
|
||||||
case 59:
|
|
||||||
return Function_Weather;
|
|
||||||
case 60:
|
|
||||||
return Function_PcVampire;
|
|
||||||
case 61:
|
|
||||||
return Function_Level;
|
|
||||||
case 62:
|
|
||||||
return Function_Attacked;
|
|
||||||
case 63:
|
|
||||||
return Function_TalkedToPc;
|
|
||||||
case 64:
|
|
||||||
return Function_PcDynamicStat;
|
|
||||||
case 65:
|
|
||||||
return Function_CreatureTargetted;
|
|
||||||
case 66:
|
|
||||||
return Function_FriendlyHit;
|
|
||||||
case 67:
|
|
||||||
case 68:
|
|
||||||
case 69:
|
|
||||||
case 70:
|
|
||||||
return Function_AiSetting;
|
|
||||||
case 71:
|
|
||||||
return Function_ShouldAttack;
|
|
||||||
case 72:
|
|
||||||
return Function_Werewolf;
|
|
||||||
case 73:
|
|
||||||
return Function_WerewolfKills;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Function_False;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWDialogue::SelectWrapper::SelectWrapper(const ESM::DialInfo::SelectStruct& select)
|
|
||||||
: mSelect(select)
|
: mSelect(select)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const
|
ESM::DialogueCondition::Function MWDialogue::SelectWrapper::getFunction() const
|
||||||
{
|
{
|
||||||
char type = mSelect.mSelectRule[1];
|
return mSelect.mFunction;
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case '1':
|
|
||||||
return decodeFunction();
|
|
||||||
case '2':
|
|
||||||
return Function_Global;
|
|
||||||
case '3':
|
|
||||||
return Function_Local;
|
|
||||||
case '4':
|
|
||||||
return Function_Journal;
|
|
||||||
case '5':
|
|
||||||
return Function_Item;
|
|
||||||
case '6':
|
|
||||||
return Function_Dead;
|
|
||||||
case '7':
|
|
||||||
return Function_NotId;
|
|
||||||
case '8':
|
|
||||||
return Function_NotFaction;
|
|
||||||
case '9':
|
|
||||||
return Function_NotClass;
|
|
||||||
case 'A':
|
|
||||||
return Function_NotRace;
|
|
||||||
case 'B':
|
|
||||||
return Function_NotCell;
|
|
||||||
case 'C':
|
|
||||||
return Function_NotLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Function_None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWDialogue::SelectWrapper::getArgument() const
|
int MWDialogue::SelectWrapper::getArgument() const
|
||||||
{
|
{
|
||||||
if (mSelect.mSelectRule[1] != '1')
|
switch (mSelect.mFunction)
|
||||||
return 0;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
std::istringstream(mSelect.mSelectRule.substr(2, 2)) >> index;
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
{
|
||||||
// AI settings
|
// AI settings
|
||||||
case 67:
|
case ESM::DialogueCondition::Function_Fight:
|
||||||
return 1;
|
return 1;
|
||||||
case 68:
|
case ESM::DialogueCondition::Function_Hello:
|
||||||
return 0;
|
return 0;
|
||||||
case 69:
|
case ESM::DialogueCondition::Function_Alarm:
|
||||||
return 3;
|
return 3;
|
||||||
case 70:
|
case ESM::DialogueCondition::Function_Flee:
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// attributes
|
// attributes
|
||||||
case 10:
|
case ESM::DialogueCondition::Function_PcStrength:
|
||||||
return 0;
|
return 0;
|
||||||
case 51:
|
case ESM::DialogueCondition::Function_PcIntelligence:
|
||||||
return 1;
|
return 1;
|
||||||
case 52:
|
case ESM::DialogueCondition::Function_PcWillpower:
|
||||||
return 2;
|
return 2;
|
||||||
case 53:
|
case ESM::DialogueCondition::Function_PcAgility:
|
||||||
return 3;
|
return 3;
|
||||||
case 54:
|
case ESM::DialogueCondition::Function_PcSpeed:
|
||||||
return 4;
|
return 4;
|
||||||
case 55:
|
case ESM::DialogueCondition::Function_PcEndurance:
|
||||||
return 5;
|
return 5;
|
||||||
case 56:
|
case ESM::DialogueCondition::Function_PcPersonality:
|
||||||
return 6;
|
return 6;
|
||||||
case 57:
|
case ESM::DialogueCondition::Function_PcLuck:
|
||||||
return 7;
|
return 7;
|
||||||
|
|
||||||
// skills
|
// skills
|
||||||
case 11:
|
case ESM::DialogueCondition::Function_PcBlock:
|
||||||
return 0;
|
return 0;
|
||||||
case 12:
|
case ESM::DialogueCondition::Function_PcArmorer:
|
||||||
return 1;
|
return 1;
|
||||||
case 13:
|
case ESM::DialogueCondition::Function_PcMediumArmor:
|
||||||
return 2;
|
return 2;
|
||||||
case 14:
|
case ESM::DialogueCondition::Function_PcHeavyArmor:
|
||||||
return 3;
|
return 3;
|
||||||
case 15:
|
case ESM::DialogueCondition::Function_PcBluntWeapon:
|
||||||
return 4;
|
return 4;
|
||||||
case 16:
|
case ESM::DialogueCondition::Function_PcLongBlade:
|
||||||
return 5;
|
return 5;
|
||||||
case 17:
|
case ESM::DialogueCondition::Function_PcAxe:
|
||||||
return 6;
|
return 6;
|
||||||
case 18:
|
case ESM::DialogueCondition::Function_PcSpear:
|
||||||
return 7;
|
return 7;
|
||||||
case 19:
|
case ESM::DialogueCondition::Function_PcAthletics:
|
||||||
return 8;
|
return 8;
|
||||||
case 20:
|
case ESM::DialogueCondition::Function_PcEnchant:
|
||||||
return 9;
|
return 9;
|
||||||
case 21:
|
case ESM::DialogueCondition::Function_PcDestruction:
|
||||||
return 10;
|
return 10;
|
||||||
case 22:
|
case ESM::DialogueCondition::Function_PcAlteration:
|
||||||
return 11;
|
return 11;
|
||||||
case 23:
|
case ESM::DialogueCondition::Function_PcIllusion:
|
||||||
return 12;
|
return 12;
|
||||||
case 24:
|
case ESM::DialogueCondition::Function_PcConjuration:
|
||||||
return 13;
|
return 13;
|
||||||
case 25:
|
case ESM::DialogueCondition::Function_PcMysticism:
|
||||||
return 14;
|
return 14;
|
||||||
case 26:
|
case ESM::DialogueCondition::Function_PcRestoration:
|
||||||
return 15;
|
return 15;
|
||||||
case 27:
|
case ESM::DialogueCondition::Function_PcAlchemy:
|
||||||
return 16;
|
return 16;
|
||||||
case 28:
|
case ESM::DialogueCondition::Function_PcUnarmored:
|
||||||
return 17;
|
return 17;
|
||||||
case 29:
|
case ESM::DialogueCondition::Function_PcSecurity:
|
||||||
return 18;
|
return 18;
|
||||||
case 30:
|
case ESM::DialogueCondition::Function_PcSneak:
|
||||||
return 19;
|
return 19;
|
||||||
case 31:
|
case ESM::DialogueCondition::Function_PcAcrobatics:
|
||||||
return 20;
|
return 20;
|
||||||
case 32:
|
case ESM::DialogueCondition::Function_PcLightArmor:
|
||||||
return 21;
|
return 21;
|
||||||
case 33:
|
case ESM::DialogueCondition::Function_PcShortBlade:
|
||||||
return 22;
|
return 22;
|
||||||
case 34:
|
case ESM::DialogueCondition::Function_PcMarksman:
|
||||||
return 23;
|
return 23;
|
||||||
case 35:
|
case ESM::DialogueCondition::Function_PcMerchantile:
|
||||||
return 24;
|
return 24;
|
||||||
case 36:
|
case ESM::DialogueCondition::Function_PcSpeechcraft:
|
||||||
return 25;
|
return 25;
|
||||||
case 37:
|
case ESM::DialogueCondition::Function_PcHandToHand:
|
||||||
return 26;
|
return 26;
|
||||||
|
|
||||||
// dynamic stats
|
// dynamic stats
|
||||||
case 8:
|
case ESM::DialogueCondition::Function_PcMagicka:
|
||||||
return 1;
|
return 1;
|
||||||
case 9:
|
case ESM::DialogueCondition::Function_PcFatigue:
|
||||||
return 2;
|
return 2;
|
||||||
case 64:
|
case ESM::DialogueCondition::Function_PcHealth:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
||||||
{
|
{
|
||||||
static const Function integerFunctions[] = {
|
switch (mSelect.mFunction)
|
||||||
Function_Journal,
|
{
|
||||||
Function_Item,
|
case ESM::DialogueCondition::Function_Journal:
|
||||||
Function_Dead,
|
case ESM::DialogueCondition::Function_Item:
|
||||||
Function_Choice,
|
case ESM::DialogueCondition::Function_Dead:
|
||||||
Function_AiSetting,
|
case ESM::DialogueCondition::Function_Choice:
|
||||||
Function_PcAttribute,
|
case ESM::DialogueCondition::Function_Fight:
|
||||||
Function_PcSkill,
|
case ESM::DialogueCondition::Function_Hello:
|
||||||
Function_FriendlyHit,
|
case ESM::DialogueCondition::Function_Alarm:
|
||||||
Function_PcLevel,
|
case ESM::DialogueCondition::Function_Flee:
|
||||||
Function_PcGender,
|
case ESM::DialogueCondition::Function_PcStrength:
|
||||||
Function_PcClothingModifier,
|
case ESM::DialogueCondition::Function_PcIntelligence:
|
||||||
Function_PcCrimeLevel,
|
case ESM::DialogueCondition::Function_PcWillpower:
|
||||||
Function_RankRequirement,
|
case ESM::DialogueCondition::Function_PcAgility:
|
||||||
Function_Level,
|
case ESM::DialogueCondition::Function_PcSpeed:
|
||||||
Function_PCReputation,
|
case ESM::DialogueCondition::Function_PcEndurance:
|
||||||
Function_Weather,
|
case ESM::DialogueCondition::Function_PcPersonality:
|
||||||
Function_Reputation,
|
case ESM::DialogueCondition::Function_PcLuck:
|
||||||
Function_FactionRankDiff,
|
case ESM::DialogueCondition::Function_PcBlock:
|
||||||
Function_WerewolfKills,
|
case ESM::DialogueCondition::Function_PcArmorer:
|
||||||
Function_RankLow,
|
case ESM::DialogueCondition::Function_PcMediumArmor:
|
||||||
Function_RankHigh,
|
case ESM::DialogueCondition::Function_PcHeavyArmor:
|
||||||
Function_CreatureTargetted,
|
case ESM::DialogueCondition::Function_PcBluntWeapon:
|
||||||
// end marker
|
case ESM::DialogueCondition::Function_PcLongBlade:
|
||||||
Function_None,
|
case ESM::DialogueCondition::Function_PcAxe:
|
||||||
};
|
case ESM::DialogueCondition::Function_PcSpear:
|
||||||
|
case ESM::DialogueCondition::Function_PcAthletics:
|
||||||
static const Function numericFunctions[] = {
|
case ESM::DialogueCondition::Function_PcEnchant:
|
||||||
Function_Global,
|
case ESM::DialogueCondition::Function_PcDestruction:
|
||||||
Function_Local,
|
case ESM::DialogueCondition::Function_PcAlteration:
|
||||||
Function_NotLocal,
|
case ESM::DialogueCondition::Function_PcIllusion:
|
||||||
Function_PcDynamicStat,
|
case ESM::DialogueCondition::Function_PcConjuration:
|
||||||
Function_PcHealthPercent,
|
case ESM::DialogueCondition::Function_PcMysticism:
|
||||||
Function_HealthPercent,
|
case ESM::DialogueCondition::Function_PcRestoration:
|
||||||
// end marker
|
case ESM::DialogueCondition::Function_PcAlchemy:
|
||||||
Function_None,
|
case ESM::DialogueCondition::Function_PcUnarmored:
|
||||||
};
|
case ESM::DialogueCondition::Function_PcSecurity:
|
||||||
|
case ESM::DialogueCondition::Function_PcSneak:
|
||||||
static const Function booleanFunctions[] = {
|
case ESM::DialogueCondition::Function_PcAcrobatics:
|
||||||
Function_False,
|
case ESM::DialogueCondition::Function_PcLightArmor:
|
||||||
Function_SameGender,
|
case ESM::DialogueCondition::Function_PcShortBlade:
|
||||||
Function_SameRace,
|
case ESM::DialogueCondition::Function_PcMarksman:
|
||||||
Function_SameFaction,
|
case ESM::DialogueCondition::Function_PcMerchantile:
|
||||||
Function_PcCommonDisease,
|
case ESM::DialogueCondition::Function_PcSpeechcraft:
|
||||||
Function_PcBlightDisease,
|
case ESM::DialogueCondition::Function_PcHandToHand:
|
||||||
Function_PcCorprus,
|
case ESM::DialogueCondition::Function_FriendHit:
|
||||||
Function_PcExpelled,
|
case ESM::DialogueCondition::Function_PcLevel:
|
||||||
Function_PcVampire,
|
case ESM::DialogueCondition::Function_PcGender:
|
||||||
Function_TalkedToPc,
|
case ESM::DialogueCondition::Function_PcClothingModifier:
|
||||||
Function_Alarmed,
|
case ESM::DialogueCondition::Function_PcCrimeLevel:
|
||||||
Function_Detected,
|
case ESM::DialogueCondition::Function_RankRequirement:
|
||||||
Function_Attacked,
|
case ESM::DialogueCondition::Function_Level:
|
||||||
Function_ShouldAttack,
|
case ESM::DialogueCondition::Function_PcReputation:
|
||||||
Function_Werewolf,
|
case ESM::DialogueCondition::Function_Weather:
|
||||||
// end marker
|
case ESM::DialogueCondition::Function_Reputation:
|
||||||
Function_None,
|
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||||
};
|
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||||
|
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||||
static const Function invertedBooleanFunctions[] = {
|
case ESM::DialogueCondition::Function_FacReactionHighest:
|
||||||
Function_NotId,
|
case ESM::DialogueCondition::Function_CreatureTarget:
|
||||||
Function_NotFaction,
|
|
||||||
Function_NotClass,
|
|
||||||
Function_NotRace,
|
|
||||||
Function_NotCell,
|
|
||||||
// end marker
|
|
||||||
Function_None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Function function = getFunction();
|
|
||||||
|
|
||||||
for (int i = 0; integerFunctions[i] != Function_None; ++i)
|
|
||||||
if (integerFunctions[i] == function)
|
|
||||||
return Type_Integer;
|
return Type_Integer;
|
||||||
|
case ESM::DialogueCondition::Function_Global:
|
||||||
for (int i = 0; numericFunctions[i] != Function_None; ++i)
|
case ESM::DialogueCondition::Function_Local:
|
||||||
if (numericFunctions[i] == function)
|
case ESM::DialogueCondition::Function_NotLocal:
|
||||||
|
case ESM::DialogueCondition::Function_PcHealth:
|
||||||
|
case ESM::DialogueCondition::Function_PcMagicka:
|
||||||
|
case ESM::DialogueCondition::Function_PcFatigue:
|
||||||
|
case ESM::DialogueCondition::Function_PcHealthPercent:
|
||||||
|
case ESM::DialogueCondition::Function_Health_Percent:
|
||||||
return Type_Numeric;
|
return Type_Numeric;
|
||||||
|
case ESM::DialogueCondition::Function_SameSex:
|
||||||
for (int i = 0; booleanFunctions[i] != Function_None; ++i)
|
case ESM::DialogueCondition::Function_SameRace:
|
||||||
if (booleanFunctions[i] == function)
|
case ESM::DialogueCondition::Function_SameFaction:
|
||||||
|
case ESM::DialogueCondition::Function_PcCommonDisease:
|
||||||
|
case ESM::DialogueCondition::Function_PcBlightDisease:
|
||||||
|
case ESM::DialogueCondition::Function_PcCorpus:
|
||||||
|
case ESM::DialogueCondition::Function_PcExpelled:
|
||||||
|
case ESM::DialogueCondition::Function_PcVampire:
|
||||||
|
case ESM::DialogueCondition::Function_TalkedToPc:
|
||||||
|
case ESM::DialogueCondition::Function_Alarmed:
|
||||||
|
case ESM::DialogueCondition::Function_Detected:
|
||||||
|
case ESM::DialogueCondition::Function_Attacked:
|
||||||
|
case ESM::DialogueCondition::Function_ShouldAttack:
|
||||||
|
case ESM::DialogueCondition::Function_Werewolf:
|
||||||
return Type_Boolean;
|
return Type_Boolean;
|
||||||
|
case ESM::DialogueCondition::Function_NotId:
|
||||||
for (int i = 0; invertedBooleanFunctions[i] != Function_None; ++i)
|
case ESM::DialogueCondition::Function_NotFaction:
|
||||||
if (invertedBooleanFunctions[i] == function)
|
case ESM::DialogueCondition::Function_NotClass:
|
||||||
|
case ESM::DialogueCondition::Function_NotRace:
|
||||||
|
case ESM::DialogueCondition::Function_NotCell:
|
||||||
return Type_Inverted;
|
return Type_Inverted;
|
||||||
|
default:
|
||||||
return Type_None;
|
return Type_None;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWDialogue::SelectWrapper::isNpcOnly() const
|
bool MWDialogue::SelectWrapper::isNpcOnly() const
|
||||||
{
|
{
|
||||||
static const Function functions[] = {
|
switch (mSelect.mFunction)
|
||||||
Function_NotFaction,
|
{
|
||||||
Function_NotClass,
|
case ESM::DialogueCondition::Function_NotFaction:
|
||||||
Function_NotRace,
|
case ESM::DialogueCondition::Function_NotClass:
|
||||||
Function_SameGender,
|
case ESM::DialogueCondition::Function_NotRace:
|
||||||
Function_SameRace,
|
case ESM::DialogueCondition::Function_SameSex:
|
||||||
Function_SameFaction,
|
case ESM::DialogueCondition::Function_SameRace:
|
||||||
Function_RankRequirement,
|
case ESM::DialogueCondition::Function_SameFaction:
|
||||||
Function_Reputation,
|
case ESM::DialogueCondition::Function_RankRequirement:
|
||||||
Function_FactionRankDiff,
|
case ESM::DialogueCondition::Function_Reputation:
|
||||||
Function_Werewolf,
|
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||||
Function_WerewolfKills,
|
case ESM::DialogueCondition::Function_Werewolf:
|
||||||
Function_RankLow,
|
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||||
Function_RankHigh,
|
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||||
// end marker
|
case ESM::DialogueCondition::Function_FacReactionHighest:
|
||||||
Function_None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Function function = getFunction();
|
|
||||||
|
|
||||||
for (int i = 0; functions[i] != Function_None; ++i)
|
|
||||||
if (functions[i] == function)
|
|
||||||
return true;
|
return true;
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWDialogue::SelectWrapper::selectCompare(int value) const
|
bool MWDialogue::SelectWrapper::selectCompare(int value) const
|
||||||
|
@ -454,15 +287,15 @@ bool MWDialogue::SelectWrapper::selectCompare(bool value) const
|
||||||
|
|
||||||
std::string MWDialogue::SelectWrapper::getName() const
|
std::string MWDialogue::SelectWrapper::getName() const
|
||||||
{
|
{
|
||||||
return Misc::StringUtils::lowerCase(getCellName());
|
return Misc::StringUtils::lowerCase(mSelect.mVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view MWDialogue::SelectWrapper::getCellName() const
|
std::string_view MWDialogue::SelectWrapper::getCellName() const
|
||||||
{
|
{
|
||||||
return std::string_view(mSelect.mSelectRule).substr(5);
|
return mSelect.mVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::RefId MWDialogue::SelectWrapper::getId() const
|
ESM::RefId MWDialogue::SelectWrapper::getId() const
|
||||||
{
|
{
|
||||||
return ESM::RefId::stringRefId(getCellName());
|
return ESM::RefId::stringRefId(mSelect.mVariable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,62 +7,9 @@ namespace MWDialogue
|
||||||
{
|
{
|
||||||
class SelectWrapper
|
class SelectWrapper
|
||||||
{
|
{
|
||||||
const ESM::DialInfo::SelectStruct& mSelect;
|
const ESM::DialogueCondition& mSelect;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Function
|
|
||||||
{
|
|
||||||
Function_None,
|
|
||||||
Function_False,
|
|
||||||
Function_Journal,
|
|
||||||
Function_Item,
|
|
||||||
Function_Dead,
|
|
||||||
Function_NotId,
|
|
||||||
Function_NotFaction,
|
|
||||||
Function_NotClass,
|
|
||||||
Function_NotRace,
|
|
||||||
Function_NotCell,
|
|
||||||
Function_NotLocal,
|
|
||||||
Function_Local,
|
|
||||||
Function_Global,
|
|
||||||
Function_SameGender,
|
|
||||||
Function_SameRace,
|
|
||||||
Function_SameFaction,
|
|
||||||
Function_Choice,
|
|
||||||
Function_PcCommonDisease,
|
|
||||||
Function_PcBlightDisease,
|
|
||||||
Function_PcCorprus,
|
|
||||||
Function_AiSetting,
|
|
||||||
Function_PcAttribute,
|
|
||||||
Function_PcSkill,
|
|
||||||
Function_PcExpelled,
|
|
||||||
Function_PcVampire,
|
|
||||||
Function_FriendlyHit,
|
|
||||||
Function_TalkedToPc,
|
|
||||||
Function_PcLevel,
|
|
||||||
Function_PcHealthPercent,
|
|
||||||
Function_PcDynamicStat,
|
|
||||||
Function_PcGender,
|
|
||||||
Function_PcClothingModifier,
|
|
||||||
Function_PcCrimeLevel,
|
|
||||||
Function_RankRequirement,
|
|
||||||
Function_HealthPercent,
|
|
||||||
Function_Level,
|
|
||||||
Function_PCReputation,
|
|
||||||
Function_Weather,
|
|
||||||
Function_Reputation,
|
|
||||||
Function_Alarmed,
|
|
||||||
Function_FactionRankDiff,
|
|
||||||
Function_Detected,
|
|
||||||
Function_Attacked,
|
|
||||||
Function_ShouldAttack,
|
|
||||||
Function_CreatureTargetted,
|
|
||||||
Function_Werewolf,
|
|
||||||
Function_WerewolfKills,
|
|
||||||
Function_RankLow,
|
|
||||||
Function_RankHigh
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Type_None,
|
Type_None,
|
||||||
|
@ -72,13 +19,10 @@ namespace MWDialogue
|
||||||
Type_Inverted
|
Type_Inverted
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
Function decodeFunction() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SelectWrapper(const ESM::DialInfo::SelectStruct& select);
|
SelectWrapper(const ESM::DialogueCondition& select);
|
||||||
|
|
||||||
Function getFunction() const;
|
ESM::DialogueCondition::Function getFunction() const;
|
||||||
|
|
||||||
int getArgument() const;
|
int getArgument() const;
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ add_component_dir (esm3
|
||||||
inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats
|
inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats
|
||||||
weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
|
weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
|
||||||
aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache
|
aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache
|
||||||
infoorder timestamp formatversion landrecorddata selectiongroup
|
infoorder timestamp formatversion landrecorddata selectiongroup dialoguecondition
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (esmterrain
|
add_component_dir (esmterrain
|
||||||
|
|
204
components/esm3/dialoguecondition.cpp
Normal file
204
components/esm3/dialoguecondition.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#include "dialoguecondition.hpp"
|
||||||
|
|
||||||
|
#include "esmreader.hpp"
|
||||||
|
#include "esmwriter.hpp"
|
||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/misc/concepts.hpp>
|
||||||
|
#include <components/misc/strings/conversion.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
std::optional<DialogueCondition> DialogueCondition::load(ESMReader& esm, ESM::RefId context)
|
||||||
|
{
|
||||||
|
std::string rule = esm.getHString();
|
||||||
|
ESM::Variant variant;
|
||||||
|
variant.read(esm, Variant::Format_Info);
|
||||||
|
if (rule.size() < 5)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Found invalid SCVR rule of size " << rule.size() << " in INFO " << context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (rule[4] < '0' || rule[4] > '5')
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Found invalid SCVR comparison operator " << static_cast<int>(rule[4]) << " in INFO "
|
||||||
|
<< context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
DialogueCondition condition;
|
||||||
|
if (rule[0] >= '0' && rule[0] <= '9')
|
||||||
|
condition.mIndex = rule[0] - '0';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Info) << "Found invalid SCVR index " << static_cast<int>(rule[0]) << " in INFO " << context;
|
||||||
|
condition.mIndex = 0;
|
||||||
|
}
|
||||||
|
if (rule[1] == '1')
|
||||||
|
{
|
||||||
|
int function = Misc::StringUtils::toNumeric<int>(std::string_view{ rule }.substr(2, 2), -1);
|
||||||
|
if (function >= Function_FacReactionLowest && function <= Function_PcWerewolfKills)
|
||||||
|
condition.mFunction = static_cast<Function>(function);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Encountered invalid SCVR function index " << function << " in INFO " << context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rule[1] > '1' && rule[1] <= '9' || rule[1] >= 'A' && rule[1] <= 'C')
|
||||||
|
{
|
||||||
|
if (rule.size() == 5)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Missing variable for SCVR of type " << rule[1] << " in INFO " << context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
bool malformed = rule[3] != 'X';
|
||||||
|
if (rule[1] == '2')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_Global;
|
||||||
|
malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '3')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_Local;
|
||||||
|
malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '4')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_Journal;
|
||||||
|
malformed |= rule[2] != 'J';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '5')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_Item;
|
||||||
|
malformed |= rule[2] != 'I';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '6')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_Dead;
|
||||||
|
malformed |= rule[2] != 'D';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '7')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotId;
|
||||||
|
malformed |= rule[2] != 'X';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '8')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotFaction;
|
||||||
|
malformed |= rule[2] != 'F';
|
||||||
|
}
|
||||||
|
else if (rule[1] == '9')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotClass;
|
||||||
|
malformed |= rule[2] != 'C';
|
||||||
|
}
|
||||||
|
else if (rule[1] == 'A')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotRace;
|
||||||
|
malformed |= rule[2] != 'R';
|
||||||
|
}
|
||||||
|
else if (rule[1] == 'B')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotCell;
|
||||||
|
malformed |= rule[2] != 'L';
|
||||||
|
}
|
||||||
|
else if (rule[1] == 'C')
|
||||||
|
{
|
||||||
|
condition.mFunction = Function_NotLocal;
|
||||||
|
malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's';
|
||||||
|
}
|
||||||
|
if (malformed)
|
||||||
|
Log(Debug::Info) << "Found malformed SCVR rule in INFO " << context;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Found invalid SCVR function " << static_cast<int>(rule[1]) << " in INFO "
|
||||||
|
<< context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
condition.mComparison = static_cast<Comparison>(rule[4]);
|
||||||
|
condition.mVariable = rule.substr(5);
|
||||||
|
if (variant.getType() == VT_Int)
|
||||||
|
condition.mValue = variant.getInteger();
|
||||||
|
else if (variant.getType() == VT_Float)
|
||||||
|
condition.mValue = variant.getFloat();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Found invalid SCVR variant " << variant.getType() << " in INFO " << context;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogueCondition::save(ESMWriter& esm) const
|
||||||
|
{
|
||||||
|
auto variant = std::visit([](auto value) { return ESM::Variant(value); }, mValue);
|
||||||
|
std::string rule;
|
||||||
|
rule.reserve(5 + mVariable.size());
|
||||||
|
rule += static_cast<char>(mIndex + '0');
|
||||||
|
const auto appendVariableType = [&]() {
|
||||||
|
if (variant.getType() == VT_Float)
|
||||||
|
rule += "fX";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int32_t value = variant.getInteger();
|
||||||
|
if (static_cast<int16_t>(value) == value)
|
||||||
|
rule += "sX";
|
||||||
|
else
|
||||||
|
rule += "lX";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (mFunction == Function_Global)
|
||||||
|
{
|
||||||
|
rule += '2';
|
||||||
|
appendVariableType();
|
||||||
|
}
|
||||||
|
else if (mFunction == Function_Local)
|
||||||
|
{
|
||||||
|
rule += '3';
|
||||||
|
appendVariableType();
|
||||||
|
}
|
||||||
|
else if (mFunction == Function_Journal)
|
||||||
|
rule += "4JX";
|
||||||
|
else if (mFunction == Function_Item)
|
||||||
|
rule += "5IX";
|
||||||
|
else if (mFunction == Function_Dead)
|
||||||
|
rule += "6DX";
|
||||||
|
else if (mFunction == Function_NotId)
|
||||||
|
rule += "7XX";
|
||||||
|
else if (mFunction == Function_NotFaction)
|
||||||
|
rule += "8FX";
|
||||||
|
else if (mFunction == Function_NotClass)
|
||||||
|
rule += "9CX";
|
||||||
|
else if (mFunction == Function_NotRace)
|
||||||
|
rule += "ARX";
|
||||||
|
else if (mFunction == Function_NotCell)
|
||||||
|
rule += "BLX";
|
||||||
|
else if (mFunction == Function_NotLocal)
|
||||||
|
{
|
||||||
|
rule += 'C';
|
||||||
|
appendVariableType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rule += "100";
|
||||||
|
char* start = rule.data() + rule.size();
|
||||||
|
char* end = start;
|
||||||
|
if (mFunction < Function_PcStrength)
|
||||||
|
start--;
|
||||||
|
else
|
||||||
|
start -= 2;
|
||||||
|
auto result = std::to_chars(start, end, mFunction);
|
||||||
|
if (result.ec != std::errc())
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Failed to save SCVR rule";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rule += static_cast<char>(mComparison);
|
||||||
|
rule += mVariable;
|
||||||
|
esm.writeHNString("SCVR", rule);
|
||||||
|
variant.write(esm, Variant::Format_Info);
|
||||||
|
}
|
||||||
|
}
|
134
components/esm3/dialoguecondition.hpp
Normal file
134
components/esm3/dialoguecondition.hpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#ifndef OPENMW_ESM3_DIALOGUECONDITION_H
|
||||||
|
#define OPENMW_ESM3_DIALOGUECONDITION_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include <components/esm/refid.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
|
||||||
|
struct DialogueCondition
|
||||||
|
{
|
||||||
|
enum Function : std::int8_t
|
||||||
|
{
|
||||||
|
Function_FacReactionLowest = 0,
|
||||||
|
Function_FacReactionHighest,
|
||||||
|
Function_RankRequirement,
|
||||||
|
Function_Reputation,
|
||||||
|
Function_Health_Percent,
|
||||||
|
Function_PcReputation,
|
||||||
|
Function_PcLevel,
|
||||||
|
Function_PcHealthPercent,
|
||||||
|
Function_PcMagicka,
|
||||||
|
Function_PcFatigue,
|
||||||
|
Function_PcStrength,
|
||||||
|
Function_PcBlock,
|
||||||
|
Function_PcArmorer,
|
||||||
|
Function_PcMediumArmor,
|
||||||
|
Function_PcHeavyArmor,
|
||||||
|
Function_PcBluntWeapon,
|
||||||
|
Function_PcLongBlade,
|
||||||
|
Function_PcAxe,
|
||||||
|
Function_PcSpear,
|
||||||
|
Function_PcAthletics,
|
||||||
|
Function_PcEnchant,
|
||||||
|
Function_PcDestruction,
|
||||||
|
Function_PcAlteration,
|
||||||
|
Function_PcIllusion,
|
||||||
|
Function_PcConjuration,
|
||||||
|
Function_PcMysticism,
|
||||||
|
Function_PcRestoration,
|
||||||
|
Function_PcAlchemy,
|
||||||
|
Function_PcUnarmored,
|
||||||
|
Function_PcSecurity,
|
||||||
|
Function_PcSneak,
|
||||||
|
Function_PcAcrobatics,
|
||||||
|
Function_PcLightArmor,
|
||||||
|
Function_PcShortBlade,
|
||||||
|
Function_PcMarksman,
|
||||||
|
Function_PcMerchantile,
|
||||||
|
Function_PcSpeechcraft,
|
||||||
|
Function_PcHandToHand,
|
||||||
|
Function_PcGender,
|
||||||
|
Function_PcExpelled,
|
||||||
|
Function_PcCommonDisease,
|
||||||
|
Function_PcBlightDisease,
|
||||||
|
Function_PcClothingModifier,
|
||||||
|
Function_PcCrimeLevel,
|
||||||
|
Function_SameSex,
|
||||||
|
Function_SameRace,
|
||||||
|
Function_SameFaction,
|
||||||
|
Function_FactionRankDifference,
|
||||||
|
Function_Detected,
|
||||||
|
Function_Alarmed,
|
||||||
|
Function_Choice,
|
||||||
|
Function_PcIntelligence,
|
||||||
|
Function_PcWillpower,
|
||||||
|
Function_PcAgility,
|
||||||
|
Function_PcSpeed,
|
||||||
|
Function_PcEndurance,
|
||||||
|
Function_PcPersonality,
|
||||||
|
Function_PcLuck,
|
||||||
|
Function_PcCorpus,
|
||||||
|
Function_Weather,
|
||||||
|
Function_PcVampire,
|
||||||
|
Function_Level,
|
||||||
|
Function_Attacked,
|
||||||
|
Function_TalkedToPc,
|
||||||
|
Function_PcHealth,
|
||||||
|
Function_CreatureTarget,
|
||||||
|
Function_FriendHit,
|
||||||
|
Function_Fight,
|
||||||
|
Function_Hello,
|
||||||
|
Function_Alarm,
|
||||||
|
Function_Flee,
|
||||||
|
Function_ShouldAttack,
|
||||||
|
Function_Werewolf,
|
||||||
|
Function_PcWerewolfKills = 73,
|
||||||
|
|
||||||
|
Function_Global,
|
||||||
|
Function_Local,
|
||||||
|
Function_Journal,
|
||||||
|
Function_Item,
|
||||||
|
Function_Dead,
|
||||||
|
Function_NotId,
|
||||||
|
Function_NotFaction,
|
||||||
|
Function_NotClass,
|
||||||
|
Function_NotRace,
|
||||||
|
Function_NotCell,
|
||||||
|
Function_NotLocal,
|
||||||
|
|
||||||
|
Function_None, // Editor only
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Comparison : char
|
||||||
|
{
|
||||||
|
Comp_Eq = '0',
|
||||||
|
Comp_Ne = '1',
|
||||||
|
Comp_Gt = '2',
|
||||||
|
Comp_Ge = '3',
|
||||||
|
Comp_Ls = '4',
|
||||||
|
Comp_Le = '5',
|
||||||
|
|
||||||
|
Comp_None = ' ', // Editor only
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string mVariable;
|
||||||
|
std::variant<int32_t, float> mValue = 0;
|
||||||
|
std::uint8_t mIndex = 0;
|
||||||
|
Function mFunction = Function_None;
|
||||||
|
Comparison mComparison = Comp_None;
|
||||||
|
|
||||||
|
static std::optional<DialogueCondition> load(ESMReader& esm, ESM::RefId context);
|
||||||
|
|
||||||
|
void save(ESMWriter& esm) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,65 +3,7 @@
|
||||||
#include "esmreader.hpp"
|
#include "esmreader.hpp"
|
||||||
#include "esmwriter.hpp"
|
#include "esmwriter.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
|
||||||
#include <components/misc/concepts.hpp>
|
#include <components/misc/concepts.hpp>
|
||||||
#include <components/misc/strings/conversion.hpp>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
enum class SelectRuleStatus
|
|
||||||
{
|
|
||||||
Valid,
|
|
||||||
Invalid,
|
|
||||||
Ignorable
|
|
||||||
};
|
|
||||||
|
|
||||||
SelectRuleStatus isValidSelectRule(std::string_view rule)
|
|
||||||
{
|
|
||||||
if (rule.size() < 5)
|
|
||||||
return SelectRuleStatus::Invalid;
|
|
||||||
if (rule[4] < '0' || rule[4] > '5') // Comparison operators
|
|
||||||
return SelectRuleStatus::Invalid;
|
|
||||||
if (rule[1] == '1') // Function
|
|
||||||
{
|
|
||||||
int function = Misc::StringUtils::toNumeric<int>(rule.substr(2, 2), -1);
|
|
||||||
if (function >= 0 && function <= 73)
|
|
||||||
return SelectRuleStatus::Valid;
|
|
||||||
return SelectRuleStatus::Invalid;
|
|
||||||
}
|
|
||||||
if (rule.size() == 5) // Missing ID
|
|
||||||
return SelectRuleStatus::Invalid;
|
|
||||||
if (rule[3] != 'X')
|
|
||||||
return SelectRuleStatus::Ignorable;
|
|
||||||
constexpr auto ignorable
|
|
||||||
= [](bool valid) { return valid ? SelectRuleStatus::Valid : SelectRuleStatus::Ignorable; };
|
|
||||||
switch (rule[1])
|
|
||||||
{
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case 'C':
|
|
||||||
return ignorable(rule[2] == 's' || rule[2] == 'l' || rule[2] == 'f');
|
|
||||||
case '4':
|
|
||||||
return ignorable(rule[2] == 'J');
|
|
||||||
case '5':
|
|
||||||
return ignorable(rule[2] == 'I');
|
|
||||||
case '6':
|
|
||||||
return ignorable(rule[2] == 'D');
|
|
||||||
case '7':
|
|
||||||
return ignorable(rule[2] == 'X');
|
|
||||||
case '8':
|
|
||||||
return ignorable(rule[2] == 'F');
|
|
||||||
case '9':
|
|
||||||
return ignorable(rule[2] == 'C');
|
|
||||||
case 'A':
|
|
||||||
return ignorable(rule[2] == 'R');
|
|
||||||
case 'B':
|
|
||||||
return ignorable(rule[2] == 'L');
|
|
||||||
default:
|
|
||||||
return SelectRuleStatus::Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -124,21 +66,9 @@ namespace ESM
|
||||||
break;
|
break;
|
||||||
case fourCC("SCVR"):
|
case fourCC("SCVR"):
|
||||||
{
|
{
|
||||||
SelectStruct ss;
|
auto filter = DialogueCondition::load(esm, mId);
|
||||||
ss.mSelectRule = esm.getHString();
|
if (filter)
|
||||||
ss.mValue.read(esm, Variant::Format_Info);
|
mSelects.emplace_back(std::move(*filter));
|
||||||
auto valid = isValidSelectRule(ss.mSelectRule);
|
|
||||||
if (ss.mValue.getType() != VT_Int && ss.mValue.getType() != VT_Float)
|
|
||||||
valid = SelectRuleStatus::Invalid;
|
|
||||||
if (valid == SelectRuleStatus::Invalid)
|
|
||||||
Log(Debug::Warning) << "Skipping invalid SCVR for INFO " << mId;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSelects.push_back(ss);
|
|
||||||
if (valid == SelectRuleStatus::Ignorable)
|
|
||||||
Log(Debug::Info)
|
|
||||||
<< "Found malformed SCVR for INFO " << mId << " at index " << ss.mSelectRule[0];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case fourCC("BNAM"):
|
case fourCC("BNAM"):
|
||||||
|
@ -189,11 +119,8 @@ namespace ESM
|
||||||
esm.writeHNOCString("SNAM", mSound);
|
esm.writeHNOCString("SNAM", mSound);
|
||||||
esm.writeHNOString("NAME", mResponse);
|
esm.writeHNOString("NAME", mResponse);
|
||||||
|
|
||||||
for (std::vector<SelectStruct>::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it)
|
for (const auto& rule : mSelects)
|
||||||
{
|
rule.save(esm);
|
||||||
esm.writeHNString("SCVR", it->mSelectRule);
|
|
||||||
it->mValue.write(esm, Variant::Format_Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
esm.writeHNOString("BNAM", mResultScript);
|
esm.writeHNOString("BNAM", mResultScript);
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "components/esm/defs.hpp"
|
#include <components/esm/defs.hpp>
|
||||||
#include "components/esm/refid.hpp"
|
#include <components/esm/refid.hpp>
|
||||||
|
|
||||||
|
#include "dialoguecondition.hpp"
|
||||||
#include "variant.hpp"
|
#include "variant.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
@ -47,13 +49,6 @@ namespace ESM
|
||||||
}; // 12 bytes
|
}; // 12 bytes
|
||||||
DATAstruct mData;
|
DATAstruct mData;
|
||||||
|
|
||||||
// The rules for whether or not we will select this dialog item.
|
|
||||||
struct SelectStruct
|
|
||||||
{
|
|
||||||
std::string mSelectRule; // This has a complicated format
|
|
||||||
Variant mValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Journal quest indices (introduced with the quest system in Tribunal)
|
// Journal quest indices (introduced with the quest system in Tribunal)
|
||||||
enum QuestStatus
|
enum QuestStatus
|
||||||
{
|
{
|
||||||
|
@ -65,7 +60,7 @@ namespace ESM
|
||||||
|
|
||||||
// Rules for when to include this item in the final list of options
|
// Rules for when to include this item in the final list of options
|
||||||
// visible to the player.
|
// visible to the player.
|
||||||
std::vector<SelectStruct> mSelects;
|
std::vector<DialogueCondition> mSelects;
|
||||||
|
|
||||||
// Id of this, previous and next INFO items
|
// Id of this, previous and next INFO items
|
||||||
RefId mId, mPrev, mNext;
|
RefId mId, mPrev, mNext;
|
||||||
|
|
Loading…
Reference in a new issue