mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
7.1 KiB
C++
207 lines
7.1 KiB
C++
#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);
|
|
if (variant.getType() != VT_Float)
|
|
variant.setType(VT_Int);
|
|
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, static_cast<int>(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);
|
|
}
|
|
}
|