mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 05:56:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			206 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			206 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);
 | |
|     }
 | |
| }
 |