mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 21:35:24 +00:00
Deduplicate dialogue filter parsing
This commit is contained in:
parent
fb4edda45d
commit
a4625ea784
@ -1,5 +1,6 @@
|
||||
#include "labels.hpp"
|
||||
|
||||
#include <components/esm3/dialoguecondition.hpp>
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadbody.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
@ -572,13 +573,14 @@ std::string_view enchantTypeLabel(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[] = {
|
||||
"Reaction Low",
|
||||
"Reaction High",
|
||||
"Lowest Faction Reaction",
|
||||
"Highest Faction Reaction",
|
||||
"Rank Requirement",
|
||||
"NPC? Reputation",
|
||||
"NPC Reputation",
|
||||
"Health Percent",
|
||||
"Player Reputation",
|
||||
"NPC Level",
|
||||
@ -648,6 +650,7 @@ std::string_view ruleFunction(int idx)
|
||||
"Flee",
|
||||
"Should Attack",
|
||||
"Werewolf",
|
||||
"Werewolf Kills",
|
||||
};
|
||||
return ruleFunctions[idx];
|
||||
}
|
||||
|
@ -57,112 +57,82 @@ namespace
|
||||
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)
|
||||
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)
|
||||
switch (ss.mFunction)
|
||||
{
|
||||
case '1':
|
||||
type_str = "Function";
|
||||
func_str = std::string(ruleFunction(func));
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
type_str = "Global";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '2':
|
||||
if (indicator == 's')
|
||||
type_str = "Global short";
|
||||
else if (indicator == 'l')
|
||||
type_str = "Global long";
|
||||
else if (indicator == 'f')
|
||||
type_str = "Global float";
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
type_str = "Local";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '3':
|
||||
if (indicator == 's')
|
||||
type_str = "Local short";
|
||||
else if (indicator == 'l')
|
||||
type_str = "Local long";
|
||||
else if (indicator == 'f')
|
||||
type_str = "Local float";
|
||||
case ESM::DialogueCondition::Function_Journal:
|
||||
type_str = "Journal";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '4':
|
||||
if (indicator == 'J')
|
||||
type_str = "Journal";
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
type_str = "Item count";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '5':
|
||||
if (indicator == 'I')
|
||||
type_str = "Item type";
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
type_str = "Dead";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '6':
|
||||
if (indicator == 'D')
|
||||
type_str = "NPC Dead";
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
type_str = "Not ID";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '7':
|
||||
if (indicator == 'X')
|
||||
type_str = "Not ID";
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
type_str = "Not Faction";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '8':
|
||||
if (indicator == 'F')
|
||||
type_str = "Not Faction";
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
type_str = "Not Class";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '9':
|
||||
if (indicator == 'C')
|
||||
type_str = "Not Class";
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
type_str = "Not Race";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case 'A':
|
||||
if (indicator == 'R')
|
||||
type_str = "Not Race";
|
||||
case ESM::DialogueCondition::Function_NotCell:
|
||||
type_str = "Not Cell";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case 'B':
|
||||
if (indicator == 'L')
|
||||
type_str = "Not Cell";
|
||||
break;
|
||||
case 'C':
|
||||
if (indicator == 's')
|
||||
type_str = "Not Local";
|
||||
case ESM::DialogueCondition::Function_NotLocal:
|
||||
type_str = "Not Local";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
default:
|
||||
type_str = "Function";
|
||||
func_str = ruleFunction(ss.mFunction);
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the variable name to the function string if any.
|
||||
if (type != '1')
|
||||
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)
|
||||
std::string_view oper_str = "??";
|
||||
switch (ss.mComparison)
|
||||
{
|
||||
case '0':
|
||||
case ESM::DialogueCondition::Comp_Eq:
|
||||
oper_str = "==";
|
||||
break;
|
||||
case '1':
|
||||
case ESM::DialogueCondition::Comp_Ne:
|
||||
oper_str = "!=";
|
||||
break;
|
||||
case '2':
|
||||
case ESM::DialogueCondition::Comp_Gt:
|
||||
oper_str = "> ";
|
||||
break;
|
||||
case '3':
|
||||
case ESM::DialogueCondition::Comp_Ge:
|
||||
oper_str = ">=";
|
||||
break;
|
||||
case '4':
|
||||
case ESM::DialogueCondition::Comp_Ls:
|
||||
oper_str = "< ";
|
||||
break;
|
||||
case '5':
|
||||
case ESM::DialogueCondition::Comp_Le:
|
||||
oper_str = "<=";
|
||||
break;
|
||||
default:
|
||||
@ -170,7 +140,7 @@ namespace
|
||||
}
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << ss.mValue;
|
||||
std::visit([&](auto value) { stream << value; }, ss.mValue);
|
||||
|
||||
std::string result
|
||||
= Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str());
|
||||
@ -842,7 +812,7 @@ namespace EsmTool
|
||||
<< 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;
|
||||
|
||||
if (!mData.mResultScript.empty())
|
||||
|
@ -171,10 +171,9 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message
|
||||
|
||||
// Check info conditions
|
||||
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator it = topicInfo.mSelects.begin();
|
||||
it != topicInfo.mSelects.end(); ++it)
|
||||
for (const auto& select : topicInfo.mSelects)
|
||||
{
|
||||
verifySelectStruct((*it), id, messages);
|
||||
verifySelectStruct(select, id, messages);
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,49 +307,15 @@ bool CSMTools::TopicInfoCheckStage::verifyItem(
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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())
|
||||
{
|
||||
messages.add(
|
||||
@ -365,48 +330,48 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
||||
}
|
||||
|
||||
// Id checks
|
||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mGlobals, id, messages))
|
||||
if (select.mFunction == ESM::DialogueCondition::Function_Global
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mGlobals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mJournals, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Journal
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mJournals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item
|
||||
&& !verifyItem(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Item
|
||||
&& !verifyItem(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead
|
||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Dead
|
||||
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId
|
||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotId
|
||||
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mFactions, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotFaction
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mFactions, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mClasses, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotClass
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mClasses, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mRaces, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotRace
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mRaces, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell
|
||||
&& !verifyCell(infoCondition.getVariableName(), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotCell
|
||||
&& !verifyCell(select.mVariable, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ namespace CSMTools
|
||||
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 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);
|
||||
|
||||
template <typename T>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,133 +7,13 @@
|
||||
|
||||
#include <components/esm3/loadinfo.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Variant;
|
||||
}
|
||||
#include <QVariant>
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
Comparison_Boolean,
|
||||
@ -143,25 +23,18 @@ namespace CSMWorld
|
||||
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* RelationEnumStrings[];
|
||||
static const char* ComparisonEnumStrings[];
|
||||
|
||||
static std::string convertToString(FunctionName name);
|
||||
static std::string convertToString(RelationType type);
|
||||
static std::string convertToString(ESM::DialogueCondition::Function name);
|
||||
static std::string convertToString(ESM::DialogueCondition::Comparison type);
|
||||
static std::string convertToString(ComparisonType type);
|
||||
|
||||
ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select);
|
||||
ConstInfoSelectWrapper(const ESM::DialogueCondition& select);
|
||||
|
||||
FunctionName getFunctionName() const;
|
||||
RelationType getRelationType() const;
|
||||
ESM::DialogueCondition::Function getFunctionName() const;
|
||||
ESM::DialogueCondition::Comparison getRelationType() const;
|
||||
ComparisonType getComparisonType() const;
|
||||
|
||||
bool hasVariable() const;
|
||||
@ -169,17 +42,12 @@ namespace CSMWorld
|
||||
|
||||
bool conditionIsAlwaysTrue() const;
|
||||
bool conditionIsNeverTrue() const;
|
||||
bool variantTypeIsValid() const;
|
||||
|
||||
const ESM::Variant& getVariant() const;
|
||||
QVariant getValue() const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
protected:
|
||||
void readRule();
|
||||
void readFunctionName();
|
||||
void readRelationType();
|
||||
void readVariableName();
|
||||
void updateHasVariable();
|
||||
void updateComparisonType();
|
||||
|
||||
@ -207,38 +75,29 @@ namespace CSMWorld
|
||||
template <typename Type1, typename Type2>
|
||||
bool conditionIsNeverTrue(std::pair<Type1, Type1> conditionRange, std::pair<Type2, Type2> validRange) const;
|
||||
|
||||
FunctionName mFunctionName;
|
||||
RelationType mRelationType;
|
||||
ComparisonType mComparisonType;
|
||||
|
||||
bool mHasVariable;
|
||||
std::string mVariableName;
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
InfoSelectWrapper(ESM::DialInfo::SelectStruct& select);
|
||||
InfoSelectWrapper(ESM::DialogueCondition& select);
|
||||
|
||||
// Wrapped SelectStruct will not be modified until update() is called
|
||||
void setFunctionName(FunctionName name);
|
||||
void setRelationType(RelationType type);
|
||||
void setFunctionName(ESM::DialogueCondition::Function name);
|
||||
void setRelationType(ESM::DialogueCondition::Comparison type);
|
||||
void setVariableName(const std::string& name);
|
||||
|
||||
// Modified wrapped SelectStruct
|
||||
void update();
|
||||
|
||||
// This sets properties based on the function name to its defaults and updates the wrapped object
|
||||
void setDefaults();
|
||||
|
||||
ESM::Variant& getVariant();
|
||||
void setValue(int value);
|
||||
void setValue(float value);
|
||||
|
||||
private:
|
||||
ESM::DialInfo::SelectStruct& mSelect;
|
||||
ESM::DialogueCondition& mSelect;
|
||||
|
||||
void writeRule();
|
||||
};
|
||||
|
@ -538,13 +538,11 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
||||
auto& conditions = info.mSelects;
|
||||
|
||||
// default row
|
||||
ESM::DialInfo::SelectStruct condStruct;
|
||||
condStruct.mSelectRule = "01000";
|
||||
condStruct.mValue = ESM::Variant();
|
||||
condStruct.mValue.setType(ESM::VT_Int);
|
||||
ESM::DialogueCondition condStruct;
|
||||
condStruct.mIndex = conditions.size();
|
||||
|
||||
conditions.insert(conditions.begin() + position, condStruct);
|
||||
|
||||
@ -555,7 +553,7 @@ namespace CSMWorld
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -569,8 +567,8 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
info.mSelects = static_cast<const NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>&>(nestedTable)
|
||||
.mNestedTable;
|
||||
info.mSelects
|
||||
= static_cast<const NestedTableWrapper<std::vector<ESM::DialogueCondition>>&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified(info);
|
||||
}
|
||||
@ -578,14 +576,14 @@ namespace CSMWorld
|
||||
NestedTableWrapperBase* InfoConditionAdapter::table(const Record<Info>& record) const
|
||||
{
|
||||
// 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
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -611,19 +609,7 @@ namespace CSMWorld
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
switch (infoSelectWrapper.getVariant().getType())
|
||||
{
|
||||
case ESM::VT_Int:
|
||||
{
|
||||
return infoSelectWrapper.getVariant().getInteger();
|
||||
}
|
||||
case ESM::VT_Float:
|
||||
{
|
||||
return infoSelectWrapper.getVariant().getFloat();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
return infoSelectWrapper.getValue();
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Info condition subcolumn index out of range");
|
||||
@ -635,7 +621,7 @@ namespace CSMWorld
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -647,27 +633,17 @@ namespace CSMWorld
|
||||
{
|
||||
case 0: // Function
|
||||
{
|
||||
infoSelectWrapper.setFunctionName(static_cast<ConstInfoSelectWrapper::FunctionName>(value.toInt()));
|
||||
|
||||
if (infoSelectWrapper.getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric
|
||||
&& infoSelectWrapper.getVariant().getType() != ESM::VT_Int)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
}
|
||||
|
||||
infoSelectWrapper.update();
|
||||
infoSelectWrapper.setFunctionName(static_cast<ESM::DialogueCondition::Function>(value.toInt()));
|
||||
break;
|
||||
}
|
||||
case 1: // Variable
|
||||
{
|
||||
infoSelectWrapper.setVariableName(value.toString().toUtf8().constData());
|
||||
infoSelectWrapper.update();
|
||||
break;
|
||||
}
|
||||
case 2: // Relation
|
||||
{
|
||||
infoSelectWrapper.setRelationType(static_cast<ConstInfoSelectWrapper::RelationType>(value.toInt()));
|
||||
infoSelectWrapper.update();
|
||||
infoSelectWrapper.setRelationType(static_cast<ESM::DialogueCondition::Comparison>(value.toInt()));
|
||||
break;
|
||||
}
|
||||
case 3: // Value
|
||||
@ -679,13 +655,11 @@ namespace CSMWorld
|
||||
// QVariant seems to have issues converting 0
|
||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
||||
infoSelectWrapper.setValue(value.toInt());
|
||||
}
|
||||
else if (value.toFloat(&conversionResult) && conversionResult)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Float);
|
||||
infoSelectWrapper.getVariant().setFloat(value.toFloat());
|
||||
infoSelectWrapper.setValue(value.toFloat());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -694,8 +668,7 @@ namespace CSMWorld
|
||||
{
|
||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
||||
infoSelectWrapper.setValue(value.toInt());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -46,41 +46,41 @@ QWidget* CSVWorld::IdCompletionDelegate::createEditor(QWidget* parent, const QSt
|
||||
|
||||
switch (conditionFunction)
|
||||
{
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Global:
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
{
|
||||
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);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Item:
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Dead:
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotId:
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
{
|
||||
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);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotClass:
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
{
|
||||
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);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotCell:
|
||||
case ESM::DialogueCondition::Function_NotCell:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Cell);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Local:
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotLocal:
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
case ESM::DialogueCondition::Function_NotLocal:
|
||||
{
|
||||
return new CSVWidget::DropLineEdit(display, parent);
|
||||
}
|
||||
|
@ -31,15 +31,15 @@ namespace
|
||||
bool matchesStaticFilters(const MWDialogue::SelectWrapper& select, const MWWorld::Ptr& actor)
|
||||
{
|
||||
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;
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotFaction)
|
||||
if (select.getFunction() == ESM::DialogueCondition::Function_NotFaction)
|
||||
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;
|
||||
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 true;
|
||||
@ -47,7 +47,7 @@ namespace
|
||||
|
||||
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;
|
||||
if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Boolean)
|
||||
@ -62,7 +62,7 @@ namespace
|
||||
}
|
||||
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);
|
||||
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
|
||||
{
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter(info.mSelects.begin());
|
||||
iter != info.mSelects.end(); ++iter)
|
||||
if (!testSelectStruct(*iter))
|
||||
for (const auto& select : info.mSelects)
|
||||
if (!testSelectStruct(select))
|
||||
return false;
|
||||
|
||||
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.
|
||||
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.
|
||||
return false;
|
||||
|
||||
if (select.getFunction() == SelectWrapper::Function_Weather
|
||||
if (select.getFunction() == ESM::DialogueCondition::Function_Weather
|
||||
&& !(MWBase::Environment::get().getWorld()->isCellExterior()
|
||||
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior()))
|
||||
// Reject weather conditions in interior cells
|
||||
@ -305,29 +304,31 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co
|
||||
{
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_Global:
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare(MWBase::Environment::get().getWorld()->getGlobalFloat(select.getName()));
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
{
|
||||
return testFunctionLocal(select);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_NotLocal:
|
||||
case ESM::DialogueCondition::Function_NotLocal:
|
||||
{
|
||||
return !testFunctionLocal(select);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcHealthPercent:
|
||||
case ESM::DialogueCondition::Function_PcHealthPercent:
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
return select.selectCompare(
|
||||
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();
|
||||
|
||||
@ -336,7 +337,7 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co
|
||||
return select.selectCompare(value);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_HealthPercent:
|
||||
case ESM::DialogueCondition::Function_Health_Percent:
|
||||
{
|
||||
return select.selectCompare(
|
||||
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())
|
||||
{
|
||||
case SelectWrapper::Function_Journal:
|
||||
case ESM::DialogueCondition::Function_Journal:
|
||||
|
||||
return MWBase::Environment::get().getJournal()->getJournalIndex(select.getId());
|
||||
|
||||
case SelectWrapper::Function_Item:
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
{
|
||||
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
||||
|
||||
return store.count(select.getId());
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Dead:
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
|
||||
return MWBase::Environment::get().getMechanicsManager()->countDeaths(select.getId());
|
||||
|
||||
case SelectWrapper::Function_Choice:
|
||||
case ESM::DialogueCondition::Function_Choice:
|
||||
|
||||
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();
|
||||
if (argument < 0 || argument > 3)
|
||||
@ -386,32 +390,65 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
.getAiSetting(static_cast<MWMechanics::AiSetting>(argument))
|
||||
.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());
|
||||
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());
|
||||
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();
|
||||
|
||||
return hits > 4 ? 4 : hits;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcLevel:
|
||||
case ESM::DialogueCondition::Function_PcLevel:
|
||||
|
||||
return player.getClass().getCreatureStats(player).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PcGender:
|
||||
case ESM::DialogueCondition::Function_PcGender:
|
||||
|
||||
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);
|
||||
|
||||
@ -428,11 +465,11 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
return value;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcCrimeLevel:
|
||||
case ESM::DialogueCondition::Function_PcCrimeLevel:
|
||||
|
||||
return player.getClass().getNpcStats(player).getBounty();
|
||||
|
||||
case SelectWrapper::Function_RankRequirement:
|
||||
case ESM::DialogueCondition::Function_RankRequirement:
|
||||
{
|
||||
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
||||
if (faction.empty())
|
||||
@ -454,23 +491,23 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
return result;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Level:
|
||||
case ESM::DialogueCondition::Function_Level:
|
||||
|
||||
return mActor.getClass().getCreatureStats(mActor).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PCReputation:
|
||||
case ESM::DialogueCondition::Function_PcReputation:
|
||||
|
||||
return player.getClass().getNpcStats(player).getReputation();
|
||||
|
||||
case SelectWrapper::Function_Weather:
|
||||
case ESM::DialogueCondition::Function_Weather:
|
||||
|
||||
return MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||
|
||||
case SelectWrapper::Function_Reputation:
|
||||
case ESM::DialogueCondition::Function_Reputation:
|
||||
|
||||
return mActor.getClass().getNpcStats(mActor).getReputation();
|
||||
|
||||
case SelectWrapper::Function_FactionRankDiff:
|
||||
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||
{
|
||||
const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor);
|
||||
|
||||
@ -482,14 +519,14 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
return rank - npcRank;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_WerewolfKills:
|
||||
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||
|
||||
return player.getClass().getNpcStats(player).getWerewolfKills();
|
||||
|
||||
case SelectWrapper::Function_RankLow:
|
||||
case SelectWrapper::Function_RankHigh:
|
||||
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||
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);
|
||||
|
||||
@ -512,7 +549,7 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
return value;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_CreatureTargetted:
|
||||
case ESM::DialogueCondition::Function_CreatureTarget:
|
||||
|
||||
{
|
||||
MWWorld::Ptr target;
|
||||
@ -539,53 +576,49 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_False:
|
||||
|
||||
return false;
|
||||
|
||||
case SelectWrapper::Function_NotId:
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
|
||||
return mActor.getCellRef().getRefId() != select.getId();
|
||||
|
||||
case SelectWrapper::Function_NotFaction:
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
|
||||
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();
|
||||
|
||||
case SelectWrapper::Function_NotRace:
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
|
||||
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());
|
||||
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)
|
||||
== (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;
|
||||
|
||||
case SelectWrapper::Function_SameFaction:
|
||||
case ESM::DialogueCondition::Function_SameFaction:
|
||||
|
||||
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();
|
||||
|
||||
case SelectWrapper::Function_PcBlightDisease:
|
||||
case ESM::DialogueCondition::Function_PcBlightDisease:
|
||||
|
||||
return player.getClass().getCreatureStats(player).hasBlightDisease();
|
||||
|
||||
case SelectWrapper::Function_PcCorprus:
|
||||
case ESM::DialogueCondition::Function_PcCorpus:
|
||||
|
||||
return player.getClass()
|
||||
.getCreatureStats(player)
|
||||
@ -594,7 +627,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||
.getMagnitude()
|
||||
!= 0;
|
||||
|
||||
case SelectWrapper::Function_PcExpelled:
|
||||
case ESM::DialogueCondition::Function_PcExpelled:
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcVampire:
|
||||
case ESM::DialogueCondition::Function_PcVampire:
|
||||
|
||||
return player.getClass()
|
||||
.getCreatureStats(player)
|
||||
@ -613,27 +646,27 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con
|
||||
.getMagnitude()
|
||||
> 0;
|
||||
|
||||
case SelectWrapper::Function_TalkedToPc:
|
||||
case ESM::DialogueCondition::Function_TalkedToPc:
|
||||
|
||||
return mTalkedToPlayer;
|
||||
|
||||
case SelectWrapper::Function_Alarmed:
|
||||
case ESM::DialogueCondition::Function_Alarmed:
|
||||
|
||||
return mActor.getClass().getCreatureStats(mActor).isAlarmed();
|
||||
|
||||
case SelectWrapper::Function_Detected:
|
||||
case ESM::DialogueCondition::Function_Detected:
|
||||
|
||||
return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor);
|
||||
|
||||
case SelectWrapper::Function_Attacked:
|
||||
case ESM::DialogueCondition::Function_Attacked:
|
||||
|
||||
return mActor.getClass().getCreatureStats(mActor).getAttacked();
|
||||
|
||||
case SelectWrapper::Function_ShouldAttack:
|
||||
case ESM::DialogueCondition::Function_ShouldAttack:
|
||||
|
||||
return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWMechanics::getPlayer());
|
||||
|
||||
case SelectWrapper::Function_Werewolf:
|
||||
case ESM::DialogueCondition::Function_Werewolf:
|
||||
|
||||
return mActor.getClass().getNpcStats(mActor).isWerewolf();
|
||||
|
||||
|
@ -10,21 +10,21 @@
|
||||
namespace
|
||||
{
|
||||
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)
|
||||
{
|
||||
case '0':
|
||||
case ESM::DialogueCondition::Comp_Eq:
|
||||
return value1 == value2;
|
||||
case '1':
|
||||
case ESM::DialogueCondition::Comp_Ne:
|
||||
return value1 != value2;
|
||||
case '2':
|
||||
case ESM::DialogueCondition::Comp_Gt:
|
||||
return value1 > value2;
|
||||
case '3':
|
||||
case ESM::DialogueCondition::Comp_Ge:
|
||||
return value1 >= value2;
|
||||
case '4':
|
||||
case ESM::DialogueCondition::Comp_Ls:
|
||||
return value1 < value2;
|
||||
case '5':
|
||||
case ESM::DialogueCondition::Comp_Le:
|
||||
return value1 <= value2;
|
||||
}
|
||||
|
||||
@ -32,409 +32,242 @@ namespace
|
||||
}
|
||||
|
||||
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 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");
|
||||
return std::visit(
|
||||
[&](auto value) { return selectCompareImp(select.mComparison, value1, value); }, select.mValue);
|
||||
}
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const
|
||||
{
|
||||
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)
|
||||
MWDialogue::SelectWrapper::SelectWrapper(const ESM::DialogueCondition& select)
|
||||
: mSelect(select)
|
||||
{
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const
|
||||
ESM::DialogueCondition::Function MWDialogue::SelectWrapper::getFunction() const
|
||||
{
|
||||
char type = mSelect.mSelectRule[1];
|
||||
|
||||
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;
|
||||
return mSelect.mFunction;
|
||||
}
|
||||
|
||||
int MWDialogue::SelectWrapper::getArgument() const
|
||||
{
|
||||
if (mSelect.mSelectRule[1] != '1')
|
||||
return 0;
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::istringstream(mSelect.mSelectRule.substr(2, 2)) >> index;
|
||||
|
||||
switch (index)
|
||||
switch (mSelect.mFunction)
|
||||
{
|
||||
// AI settings
|
||||
case 67:
|
||||
case ESM::DialogueCondition::Function_Fight:
|
||||
return 1;
|
||||
case 68:
|
||||
case ESM::DialogueCondition::Function_Hello:
|
||||
return 0;
|
||||
case 69:
|
||||
case ESM::DialogueCondition::Function_Alarm:
|
||||
return 3;
|
||||
case 70:
|
||||
case ESM::DialogueCondition::Function_Flee:
|
||||
return 2;
|
||||
|
||||
// attributes
|
||||
case 10:
|
||||
case ESM::DialogueCondition::Function_PcStrength:
|
||||
return 0;
|
||||
case 51:
|
||||
case ESM::DialogueCondition::Function_PcIntelligence:
|
||||
return 1;
|
||||
case 52:
|
||||
case ESM::DialogueCondition::Function_PcWillpower:
|
||||
return 2;
|
||||
case 53:
|
||||
case ESM::DialogueCondition::Function_PcAgility:
|
||||
return 3;
|
||||
case 54:
|
||||
case ESM::DialogueCondition::Function_PcSpeed:
|
||||
return 4;
|
||||
case 55:
|
||||
case ESM::DialogueCondition::Function_PcEndurance:
|
||||
return 5;
|
||||
case 56:
|
||||
case ESM::DialogueCondition::Function_PcPersonality:
|
||||
return 6;
|
||||
case 57:
|
||||
case ESM::DialogueCondition::Function_PcLuck:
|
||||
return 7;
|
||||
|
||||
// skills
|
||||
case 11:
|
||||
case ESM::DialogueCondition::Function_PcBlock:
|
||||
return 0;
|
||||
case 12:
|
||||
case ESM::DialogueCondition::Function_PcArmorer:
|
||||
return 1;
|
||||
case 13:
|
||||
case ESM::DialogueCondition::Function_PcMediumArmor:
|
||||
return 2;
|
||||
case 14:
|
||||
case ESM::DialogueCondition::Function_PcHeavyArmor:
|
||||
return 3;
|
||||
case 15:
|
||||
case ESM::DialogueCondition::Function_PcBluntWeapon:
|
||||
return 4;
|
||||
case 16:
|
||||
case ESM::DialogueCondition::Function_PcLongBlade:
|
||||
return 5;
|
||||
case 17:
|
||||
case ESM::DialogueCondition::Function_PcAxe:
|
||||
return 6;
|
||||
case 18:
|
||||
case ESM::DialogueCondition::Function_PcSpear:
|
||||
return 7;
|
||||
case 19:
|
||||
case ESM::DialogueCondition::Function_PcAthletics:
|
||||
return 8;
|
||||
case 20:
|
||||
case ESM::DialogueCondition::Function_PcEnchant:
|
||||
return 9;
|
||||
case 21:
|
||||
case ESM::DialogueCondition::Function_PcDestruction:
|
||||
return 10;
|
||||
case 22:
|
||||
case ESM::DialogueCondition::Function_PcAlteration:
|
||||
return 11;
|
||||
case 23:
|
||||
case ESM::DialogueCondition::Function_PcIllusion:
|
||||
return 12;
|
||||
case 24:
|
||||
case ESM::DialogueCondition::Function_PcConjuration:
|
||||
return 13;
|
||||
case 25:
|
||||
case ESM::DialogueCondition::Function_PcMysticism:
|
||||
return 14;
|
||||
case 26:
|
||||
case ESM::DialogueCondition::Function_PcRestoration:
|
||||
return 15;
|
||||
case 27:
|
||||
case ESM::DialogueCondition::Function_PcAlchemy:
|
||||
return 16;
|
||||
case 28:
|
||||
case ESM::DialogueCondition::Function_PcUnarmored:
|
||||
return 17;
|
||||
case 29:
|
||||
case ESM::DialogueCondition::Function_PcSecurity:
|
||||
return 18;
|
||||
case 30:
|
||||
case ESM::DialogueCondition::Function_PcSneak:
|
||||
return 19;
|
||||
case 31:
|
||||
case ESM::DialogueCondition::Function_PcAcrobatics:
|
||||
return 20;
|
||||
case 32:
|
||||
case ESM::DialogueCondition::Function_PcLightArmor:
|
||||
return 21;
|
||||
case 33:
|
||||
case ESM::DialogueCondition::Function_PcShortBlade:
|
||||
return 22;
|
||||
case 34:
|
||||
case ESM::DialogueCondition::Function_PcMarksman:
|
||||
return 23;
|
||||
case 35:
|
||||
case ESM::DialogueCondition::Function_PcMerchantile:
|
||||
return 24;
|
||||
case 36:
|
||||
case ESM::DialogueCondition::Function_PcSpeechcraft:
|
||||
return 25;
|
||||
case 37:
|
||||
case ESM::DialogueCondition::Function_PcHandToHand:
|
||||
return 26;
|
||||
|
||||
// dynamic stats
|
||||
case 8:
|
||||
case ESM::DialogueCondition::Function_PcMagicka:
|
||||
return 1;
|
||||
case 9:
|
||||
case ESM::DialogueCondition::Function_PcFatigue:
|
||||
return 2;
|
||||
case 64:
|
||||
case ESM::DialogueCondition::Function_PcHealth:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
||||
{
|
||||
static const Function integerFunctions[] = {
|
||||
Function_Journal,
|
||||
Function_Item,
|
||||
Function_Dead,
|
||||
Function_Choice,
|
||||
Function_AiSetting,
|
||||
Function_PcAttribute,
|
||||
Function_PcSkill,
|
||||
Function_FriendlyHit,
|
||||
Function_PcLevel,
|
||||
Function_PcGender,
|
||||
Function_PcClothingModifier,
|
||||
Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_Level,
|
||||
Function_PCReputation,
|
||||
Function_Weather,
|
||||
Function_Reputation,
|
||||
Function_FactionRankDiff,
|
||||
Function_WerewolfKills,
|
||||
Function_RankLow,
|
||||
Function_RankHigh,
|
||||
Function_CreatureTargetted,
|
||||
// end marker
|
||||
Function_None,
|
||||
};
|
||||
|
||||
static const Function numericFunctions[] = {
|
||||
Function_Global,
|
||||
Function_Local,
|
||||
Function_NotLocal,
|
||||
Function_PcDynamicStat,
|
||||
Function_PcHealthPercent,
|
||||
Function_HealthPercent,
|
||||
// end marker
|
||||
Function_None,
|
||||
};
|
||||
|
||||
static const Function booleanFunctions[] = {
|
||||
Function_False,
|
||||
Function_SameGender,
|
||||
Function_SameRace,
|
||||
Function_SameFaction,
|
||||
Function_PcCommonDisease,
|
||||
Function_PcBlightDisease,
|
||||
Function_PcCorprus,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire,
|
||||
Function_TalkedToPc,
|
||||
Function_Alarmed,
|
||||
Function_Detected,
|
||||
Function_Attacked,
|
||||
Function_ShouldAttack,
|
||||
Function_Werewolf,
|
||||
// end marker
|
||||
Function_None,
|
||||
};
|
||||
|
||||
static const Function invertedBooleanFunctions[] = {
|
||||
Function_NotId,
|
||||
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)
|
||||
switch (mSelect.mFunction)
|
||||
{
|
||||
case ESM::DialogueCondition::Function_Journal:
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
case ESM::DialogueCondition::Function_Choice:
|
||||
case ESM::DialogueCondition::Function_Fight:
|
||||
case ESM::DialogueCondition::Function_Hello:
|
||||
case ESM::DialogueCondition::Function_Alarm:
|
||||
case ESM::DialogueCondition::Function_Flee:
|
||||
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:
|
||||
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:
|
||||
case ESM::DialogueCondition::Function_FriendHit:
|
||||
case ESM::DialogueCondition::Function_PcLevel:
|
||||
case ESM::DialogueCondition::Function_PcGender:
|
||||
case ESM::DialogueCondition::Function_PcClothingModifier:
|
||||
case ESM::DialogueCondition::Function_PcCrimeLevel:
|
||||
case ESM::DialogueCondition::Function_RankRequirement:
|
||||
case ESM::DialogueCondition::Function_Level:
|
||||
case ESM::DialogueCondition::Function_PcReputation:
|
||||
case ESM::DialogueCondition::Function_Weather:
|
||||
case ESM::DialogueCondition::Function_Reputation:
|
||||
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||
case ESM::DialogueCondition::Function_FacReactionHighest:
|
||||
case ESM::DialogueCondition::Function_CreatureTarget:
|
||||
return Type_Integer;
|
||||
|
||||
for (int i = 0; numericFunctions[i] != Function_None; ++i)
|
||||
if (numericFunctions[i] == function)
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
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;
|
||||
|
||||
for (int i = 0; booleanFunctions[i] != Function_None; ++i)
|
||||
if (booleanFunctions[i] == function)
|
||||
case ESM::DialogueCondition::Function_SameSex:
|
||||
case ESM::DialogueCondition::Function_SameRace:
|
||||
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;
|
||||
|
||||
for (int i = 0; invertedBooleanFunctions[i] != Function_None; ++i)
|
||||
if (invertedBooleanFunctions[i] == function)
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
case ESM::DialogueCondition::Function_NotCell:
|
||||
return Type_Inverted;
|
||||
|
||||
return Type_None;
|
||||
default:
|
||||
return Type_None;
|
||||
};
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::isNpcOnly() const
|
||||
{
|
||||
static const Function functions[] = {
|
||||
Function_NotFaction,
|
||||
Function_NotClass,
|
||||
Function_NotRace,
|
||||
Function_SameGender,
|
||||
Function_SameRace,
|
||||
Function_SameFaction,
|
||||
Function_RankRequirement,
|
||||
Function_Reputation,
|
||||
Function_FactionRankDiff,
|
||||
Function_Werewolf,
|
||||
Function_WerewolfKills,
|
||||
Function_RankLow,
|
||||
Function_RankHigh,
|
||||
// end marker
|
||||
Function_None,
|
||||
};
|
||||
|
||||
Function function = getFunction();
|
||||
|
||||
for (int i = 0; functions[i] != Function_None; ++i)
|
||||
if (functions[i] == function)
|
||||
switch (mSelect.mFunction)
|
||||
{
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
case ESM::DialogueCondition::Function_SameSex:
|
||||
case ESM::DialogueCondition::Function_SameRace:
|
||||
case ESM::DialogueCondition::Function_SameFaction:
|
||||
case ESM::DialogueCondition::Function_RankRequirement:
|
||||
case ESM::DialogueCondition::Function_Reputation:
|
||||
case ESM::DialogueCondition::Function_FactionRankDifference:
|
||||
case ESM::DialogueCondition::Function_Werewolf:
|
||||
case ESM::DialogueCondition::Function_PcWerewolfKills:
|
||||
case ESM::DialogueCondition::Function_FacReactionLowest:
|
||||
case ESM::DialogueCondition::Function_FacReactionHighest:
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare(int value) const
|
||||
@ -454,15 +287,15 @@ bool MWDialogue::SelectWrapper::selectCompare(bool value) 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
|
||||
{
|
||||
return std::string_view(mSelect.mSelectRule).substr(5);
|
||||
return mSelect.mVariable;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
const ESM::DialInfo::SelectStruct& mSelect;
|
||||
const ESM::DialogueCondition& mSelect;
|
||||
|
||||
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
|
||||
{
|
||||
Type_None,
|
||||
@ -72,13 +19,10 @@ namespace MWDialogue
|
||||
Type_Inverted
|
||||
};
|
||||
|
||||
private:
|
||||
Function decodeFunction() const;
|
||||
|
||||
public:
|
||||
SelectWrapper(const ESM::DialInfo::SelectStruct& select);
|
||||
SelectWrapper(const ESM::DialogueCondition& select);
|
||||
|
||||
Function getFunction() const;
|
||||
ESM::DialogueCondition::Function getFunction() const;
|
||||
|
||||
int getArgument() const;
|
||||
|
||||
|
@ -181,7 +181,7 @@ add_component_dir (esm3
|
||||
inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats
|
||||
weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
|
||||
aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache
|
||||
infoorder timestamp formatversion landrecorddata selectiongroup
|
||||
infoorder timestamp formatversion landrecorddata selectiongroup dialoguecondition
|
||||
)
|
||||
|
||||
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 "esmwriter.hpp"
|
||||
|
||||
#include <components/debug/debuglog.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
|
||||
{
|
||||
@ -124,21 +66,9 @@ namespace ESM
|
||||
break;
|
||||
case fourCC("SCVR"):
|
||||
{
|
||||
SelectStruct ss;
|
||||
ss.mSelectRule = esm.getHString();
|
||||
ss.mValue.read(esm, Variant::Format_Info);
|
||||
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];
|
||||
}
|
||||
auto filter = DialogueCondition::load(esm, mId);
|
||||
if (filter)
|
||||
mSelects.emplace_back(std::move(*filter));
|
||||
break;
|
||||
}
|
||||
case fourCC("BNAM"):
|
||||
@ -189,11 +119,8 @@ namespace ESM
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
esm.writeHNOString("NAME", mResponse);
|
||||
|
||||
for (std::vector<SelectStruct>::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it)
|
||||
{
|
||||
esm.writeHNString("SCVR", it->mSelectRule);
|
||||
it->mValue.write(esm, Variant::Format_Info);
|
||||
}
|
||||
for (const auto& rule : mSelects)
|
||||
rule.save(esm);
|
||||
|
||||
esm.writeHNOString("BNAM", mResultScript);
|
||||
|
||||
|
@ -4,8 +4,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "components/esm/defs.hpp"
|
||||
#include "components/esm/refid.hpp"
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
#include "dialoguecondition.hpp"
|
||||
#include "variant.hpp"
|
||||
|
||||
namespace ESM
|
||||
@ -47,13 +49,6 @@ namespace ESM
|
||||
}; // 12 bytes
|
||||
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)
|
||||
enum QuestStatus
|
||||
{
|
||||
@ -65,7 +60,7 @@ namespace ESM
|
||||
|
||||
// Rules for when to include this item in the final list of options
|
||||
// visible to the player.
|
||||
std::vector<SelectStruct> mSelects;
|
||||
std::vector<DialogueCondition> mSelects;
|
||||
|
||||
// Id of this, previous and next INFO items
|
||||
RefId mId, mPrev, mNext;
|
||||
|
Loading…
x
Reference in New Issue
Block a user