#include "dialoguecondition.hpp" #include "esmreader.hpp" #include "esmwriter.hpp" #include "variant.hpp" #include #include #include namespace ESM { std::optional 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(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(rule[0]) << " in INFO " << context; condition.mIndex = 0; } if (rule[1] == '1') { int function = Misc::StringUtils::toNumeric(std::string_view{ rule }.substr(2, 2), -1); if (function >= Function_FacReactionLowest && function <= Function_PcWerewolfKills) condition.mFunction = static_cast(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(rule[1]) << " in INFO " << context; return {}; } condition.mComparison = static_cast(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(mIndex + '0'); const auto appendVariableType = [&]() { if (variant.getType() == VT_Float) rule += "fX"; else { int32_t value = variant.getInteger(); if (static_cast(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(mFunction)); if (result.ec != std::errc()) { Log(Debug::Error) << "Failed to save SCVR rule"; return; } } rule += static_cast(mComparison); rule += mVariable; esm.writeHNString("SCVR", rule); variant.write(esm, Variant::Format_Info); } }