mirror of https://github.com/OpenMW/openmw.git
Deduplicate dialogue filter parsing
parent
fb4edda45d
commit
a4625ea784
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue