diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index b5e75a68..a777654d 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml index 0677e95d..f1de6faf 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml @@ -112,6 +112,14 @@ 1 taxAmount +
  • + WULA_Total_Tax_Amount + taxAmount + 0 + Set + true +
  • +
  • Silver $taxAmount diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml index 11c72a55..a320bc61 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml @@ -1882,7 +1882,6 @@ None (0.56, 0.62, 0.9) Wula/Building/WULA_Combat_Excavator_Icon - WULA_Buildings false Wula/Building/WULA_Combat_Excavator @@ -2332,7 +2331,6 @@ None (0.56, 0.62, 0.9) Wula/Building/WULA_Combat_Excavator_Icon - WULA_Buildings false Wula/Building/WULA_Combat_Excavator diff --git a/Source/WulaFallenEmpire/EventSystem/QuestNode/QuestNode_WriteToEventVariablesWithAdd.cs b/Source/WulaFallenEmpire/EventSystem/QuestNode/QuestNode_WriteToEventVariablesWithAdd.cs new file mode 100644 index 00000000..10a21a9b --- /dev/null +++ b/Source/WulaFallenEmpire/EventSystem/QuestNode/QuestNode_WriteToEventVariablesWithAdd.cs @@ -0,0 +1,536 @@ +using System; +using RimWorld.QuestGen; +using Verse; +using System.Collections.Generic; +using System.Linq; + +namespace WulaFallenEmpire +{ + public class QuestNode_WriteToEventVariablesWithAdd : QuestNode + { + // 要写入的变量名(在EventVariableManager中的名字) + [NoTranslate] + public SlateRef targetVariableName; + + // 要从Quest中读取的变量名(Slate中的变量) + [NoTranslate] + public SlateRef sourceVariableName; + + // 如果sourceVariableName为空,使用这个值 + public SlateRef value; + + // 写入模式 + public WriteMode writeMode = WriteMode.Set; + + // 是否检查变量已存在 + public SlateRef checkExisting = true; + + // 如果变量已存在,是否覆盖(仅用于Set模式) + public SlateRef overwrite = false; + + // 操作符(用于Add和Multiply模式) + public MathOperator mathOperator = MathOperator.Add; + + // 是否强制转换类型(当类型不匹配时) + public SlateRef forceTypeConversion = false; + + // 当类型不匹配且无法转换时的行为 + public TypeMismatchBehavior onTypeMismatch = TypeMismatchBehavior.ConvertToString; + + // 写入后是否从Slate中删除源变量 + public SlateRef removeFromSlate = false; + + // 是否记录调试信息 + public SlateRef logDebug = false; + + // 允许操作的数值类型 + public List allowedNumericTypes = new List + { + typeof(int), + typeof(float), + typeof(double), + typeof(long), + typeof(short), + typeof(decimal) + }; + + public enum WriteMode + { + Set, // 直接设置值(覆盖) + Add, // 相加(仅对数值类型) + Multiply, // 相乘(仅对数值类型) + Append, // 追加(字符串、列表等) + Min, // 取最小值(仅对数值类型) + Max, // 取最大值(仅对数值类型) + Increment // 自增1(仅对数值类型,忽略源值) + } + + public enum MathOperator + { + Add, // 加法 + Subtract, // 减法 + Multiply, // 乘法 + Divide // 除法 + } + + public enum TypeMismatchBehavior + { + ThrowError, // 抛出错误 + Skip, // 跳过操作 + ConvertToString,// 转换为字符串 + UseDefault // 使用默认值 + } + + protected override bool TestRunInt(Slate slate) + { + return RunInternal(slate, isTestRun: true); + } + + protected override void RunInt() + { + RunInternal(QuestGen.slate, isTestRun: false); + } + + private bool RunInternal(Slate slate, bool isTestRun) + { + // 获取目标变量名 + string targetName = targetVariableName.GetValue(slate); + if (string.IsNullOrEmpty(targetName)) + { + Log.Error("[QuestNode_WriteToEventVariablesWithAdd] targetVariableName is null or empty!"); + return false; + } + + // 获取要操作的值 + object sourceValue = GetSourceValue(slate); + if (sourceValue == null && writeMode != WriteMode.Increment) + { + if (logDebug.GetValue(slate)) + { + Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] No value to operate for variable '{targetName}'."); + } + return false; + } + + // 在测试运行时不需要实际写入 + if (isTestRun) + { + return true; + } + + // 获取EventVariableManager + var eventVarManager = Find.World.GetComponent(); + if (eventVarManager == null) + { + Log.Error("[QuestNode_WriteToEventVariablesWithAdd] EventVariableManager not found!"); + return false; + } + + bool variableExists = eventVarManager.HasVariable(targetName); + object currentValue = variableExists ? eventVarManager.GetVariable(targetName) : null; + + // 记录操作前的状态 + if (logDebug.GetValue(slate)) + { + Log.Message($"[QuestNode_WriteToEventVariablesWithAdd] Operation for variable '{targetName}':"); + Log.Message($" - Mode: {writeMode}"); + Log.Message($" - Current value: {currentValue ?? "[null]"} (Type: {currentValue?.GetType().Name ?? "null"})"); + Log.Message($" - Source value: {sourceValue ?? "[null]"} (Type: {sourceValue?.GetType().Name ?? "null"})"); + } + + // 根据写入模式计算新值 + object newValue = CalculateNewValue(currentValue, sourceValue, slate); + + // 如果新值为null(可能是由于类型不匹配被跳过了) + if (newValue == null) + { + if (logDebug.GetValue(slate)) + { + Log.Message($" - Operation skipped (new value is null)"); + } + return false; + } + + // 写入变量 + eventVarManager.SetVariable(targetName, newValue); + + // 写入后从Slate中删除源变量 + if (removeFromSlate.GetValue(slate) && !string.IsNullOrEmpty(sourceVariableName.GetValue(slate))) + { + slate.Remove(sourceVariableName.GetValue(slate)); + if (logDebug.GetValue(slate)) + { + Log.Message($" - Removed source variable '{sourceVariableName.GetValue(slate)}' from Slate"); + } + } + + // 验证写入 + if (logDebug.GetValue(slate)) + { + object readBackValue = eventVarManager.GetVariable(targetName); + bool writeVerified = (readBackValue == null && newValue == null) || + (readBackValue != null && readBackValue.Equals(newValue)); + + Log.Message($" - New value written: {newValue} (Type: {newValue.GetType().Name})"); + Log.Message($" - Write verified: {writeVerified}"); + if (!writeVerified) + { + Log.Warning($" - Verification failed! Expected: {newValue}, Got: {readBackValue}"); + } + } + + return true; + } + + private object GetSourceValue(Slate slate) + { + string sourceName = sourceVariableName.GetValue(slate); + + if (!string.IsNullOrEmpty(sourceName)) + { + if (slate.TryGet(sourceName, out var slateValue)) + { + return slateValue; + } + } + + return value.GetValue(slate); + } + + private object CalculateNewValue(object currentValue, object sourceValue, Slate slate) + { + switch (writeMode) + { + case WriteMode.Set: + return HandleSetMode(currentValue, sourceValue, slate); + + case WriteMode.Add: + case WriteMode.Multiply: + return HandleMathOperation(currentValue, sourceValue, writeMode == WriteMode.Add, slate); + + case WriteMode.Append: + return HandleAppendMode(currentValue, sourceValue, slate); + + case WriteMode.Min: + return HandleMinMaxMode(currentValue, sourceValue, isMin: true, slate); + + case WriteMode.Max: + return HandleMinMaxMode(currentValue, sourceValue, isMin: false, slate); + + case WriteMode.Increment: + return HandleIncrementMode(currentValue, slate); + + default: + return sourceValue; + } + } + + private object HandleSetMode(object currentValue, object sourceValue, Slate slate) + { + bool variableExists = currentValue != null; + + if (checkExisting.GetValue(slate) && variableExists) + { + if (!overwrite.GetValue(slate)) + { + if (logDebug.GetValue(slate)) + { + Log.Message($" - Variable exists and overwrite is false, keeping current value"); + } + return currentValue; // 不覆盖,返回原值 + } + } + + return sourceValue; + } + + private object HandleMathOperation(object currentValue, object sourceValue, bool isAddition, Slate slate) + { + // 如果当前值不存在,直接使用源值 + if (currentValue == null) + { + return sourceValue; + } + + // 尝试进行数学运算 + try + { + // 检查类型是否支持数学运算 + if (!IsNumericType(currentValue.GetType()) || !IsNumericType(sourceValue.GetType())) + { + return HandleTypeMismatch(currentValue, sourceValue, "non-numeric", slate); + } + + // 转换为动态类型以进行数学运算 + dynamic current = ConvertToBestNumericType(currentValue); + dynamic source = ConvertToBestNumericType(sourceValue); + + dynamic result; + + switch (mathOperator) + { + case MathOperator.Add: + result = current + source; + break; + case MathOperator.Subtract: + result = current - source; + break; + case MathOperator.Multiply: + result = current * source; + break; + case MathOperator.Divide: + if (source == 0) + { + Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Division by zero for variable operation"); + return currentValue; + } + result = current / source; + break; + default: + result = current + source; + break; + } + + // 根据配置决定返回类型 + if (forceTypeConversion.GetValue(slate)) + { + // 转换为与当前值相同的类型 + return Convert.ChangeType(result, currentValue.GetType()); + } + else + { + // 返回最佳类型(通常是double或decimal) + return result; + } + } + catch (Exception ex) + { + if (logDebug.GetValue(slate)) + { + Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Math operation failed: {ex.Message}"); + } + return currentValue; + } + } + + private object HandleAppendMode(object currentValue, object sourceValue, Slate slate) + { + // 如果当前值不存在,直接使用源值 + if (currentValue == null) + { + return sourceValue; + } + + // 处理字符串追加 + if (currentValue is string currentStr && sourceValue is string sourceStr) + { + return currentStr + sourceStr; + } + + // 处理列表追加 + if (currentValue is System.Collections.IEnumerable currentEnumerable && + sourceValue is System.Collections.IEnumerable sourceEnumerable) + { + try + { + // 尝试创建新列表并添加所有元素 + var resultList = new List(); + + foreach (var item in currentEnumerable) + resultList.Add(item); + + foreach (var item in sourceEnumerable) + resultList.Add(item); + + return resultList; + } + catch + { + // 如果列表操作失败,回退到字符串追加 + return currentValue.ToString() + sourceValue.ToString(); + } + } + + // 其他类型:转换为字符串并追加 + return currentValue.ToString() + sourceValue.ToString(); + } + + private object HandleMinMaxMode(object currentValue, object sourceValue, bool isMin, Slate slate) + { + // 如果当前值不存在,直接使用源值 + if (currentValue == null) + { + return sourceValue; + } + + // 检查类型是否支持比较 + if (!(currentValue is IComparable currentComparable) || !(sourceValue is IComparable sourceComparable)) + { + return HandleTypeMismatch(currentValue, sourceValue, "non-comparable", slate); + } + + try + { + int comparison = currentComparable.CompareTo(sourceComparable); + + if (isMin) + { + // 取最小值 + return comparison <= 0 ? currentValue : sourceValue; + } + else + { + // 取最大值 + return comparison >= 0 ? currentValue : sourceValue; + } + } + catch (ArgumentException) + { + // 类型不匹配,无法比较 + return HandleTypeMismatch(currentValue, sourceValue, "type mismatch for comparison", slate); + } + } + + private object HandleIncrementMode(object currentValue, Slate slate) + { + // 如果当前值不存在,从1开始 + if (currentValue == null) + { + return 1; + } + + // 检查是否是数值类型 + if (!IsNumericType(currentValue.GetType())) + { + if (logDebug.GetValue(slate)) + { + Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] Cannot increment non-numeric type: {currentValue.GetType().Name}"); + } + return currentValue; + } + + try + { + dynamic current = ConvertToBestNumericType(currentValue); + dynamic result = current + 1; + + if (forceTypeConversion.GetValue(slate)) + { + return Convert.ChangeType(result, currentValue.GetType()); + } + else + { + return result; + } + } + catch (Exception ex) + { + if (logDebug.GetValue(slate)) + { + Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Increment operation failed: {ex.Message}"); + } + return currentValue; + } + } + + private object HandleTypeMismatch(object currentValue, object sourceValue, string mismatchReason, Slate slate) + { + if (logDebug.GetValue(slate)) + { + Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] Type mismatch for operation: {mismatchReason}"); + } + + switch (onTypeMismatch) + { + case TypeMismatchBehavior.ThrowError: + throw new InvalidOperationException($"Type mismatch for operation: {mismatchReason}"); + + case TypeMismatchBehavior.Skip: + if (logDebug.GetValue(slate)) + { + Log.Message($" - Skipping operation due to type mismatch"); + } + return currentValue; // 保持原值 + + case TypeMismatchBehavior.ConvertToString: + // 都转换为字符串 + return currentValue.ToString() + " | " + sourceValue.ToString(); + + case TypeMismatchBehavior.UseDefault: + // 使用源值作为默认 + return sourceValue; + + default: + return currentValue; + } + } + + private bool IsNumericType(Type type) + { + if (type == null) return false; + + TypeCode typeCode = Type.GetTypeCode(type); + switch (typeCode) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Decimal: + case TypeCode.Double: + case TypeCode.Single: + return true; + default: + return false; + } + } + + private dynamic ConvertToBestNumericType(object value) + { + if (value == null) return 0; + + Type type = value.GetType(); + TypeCode typeCode = Type.GetTypeCode(type); + + switch (typeCode) + { + case TypeCode.Decimal: + return (decimal)value; + case TypeCode.Double: + return (double)value; + case TypeCode.Single: + return (float)value; + case TypeCode.Int64: + return (long)value; + case TypeCode.Int32: + return (int)value; + case TypeCode.Int16: + return (short)value; + case TypeCode.UInt64: + return (ulong)value; + case TypeCode.UInt32: + return (uint)value; + case TypeCode.UInt16: + return (ushort)value; + case TypeCode.Byte: + return (byte)value; + case TypeCode.SByte: + return (sbyte)value; + default: + // 尝试转换 + try + { + return Convert.ToDouble(value); + } + catch + { + return 0; + } + } + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 5f7afa9f..643c4bb5 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -70,7 +70,335 @@ ..\..\..\..\..\..\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.TextRenderingModule.dll False - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +