diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 9c18bfcf..74c21857 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/Source/WulaFallenEmpire/EventSystem/Condition.cs b/Source/WulaFallenEmpire/EventSystem/Condition.cs index 76734592..68127d30 100644 --- a/Source/WulaFallenEmpire/EventSystem/Condition.cs +++ b/Source/WulaFallenEmpire/EventSystem/Condition.cs @@ -16,17 +16,18 @@ namespace WulaFallenEmpire public override bool IsMet(out string reason) { - if (!EventContext.HasVariable(name)) + var eventVarManager = Find.World.GetComponent(); + if (!eventVarManager.HasVariable(name)) { - EventContext.SetVariable(name, "0"); + eventVarManager.SetVariable(name, "0"); } - object variable = EventContext.GetVariable(name); + object variable = eventVarManager.GetVariable(name); string compareValue = value; if (!string.IsNullOrEmpty(valueVariableName)) { - compareValue = EventContext.GetVariable(valueVariableName)?.ToString(); + compareValue = eventVarManager.GetVariable(valueVariableName)?.ToString(); if (compareValue == null) { reason = $"Comparison variable '{valueVariableName}' not set."; @@ -58,17 +59,18 @@ namespace WulaFallenEmpire public override bool IsMet(out string reason) { - if (!EventContext.HasVariable(name)) + var eventVarManager = Find.World.GetComponent(); + if (!eventVarManager.HasVariable(name)) { - EventContext.SetVariable(name, 0f); + eventVarManager.SetVariable(name, 0f); } - float variable = EventContext.GetVariable(name); + float variable = eventVarManager.GetVariable(name); float compareValue = value; if (!string.IsNullOrEmpty(valueVariableName)) { - compareValue = EventContext.GetVariable(valueVariableName, float.NaN); + compareValue = eventVarManager.GetVariable(valueVariableName, float.NaN); if (float.IsNaN(compareValue)) { reason = $"Comparison variable '{valueVariableName}' not set or not a number."; @@ -121,17 +123,18 @@ namespace WulaFallenEmpire public override bool IsMet(out string reason) { - if (!EventContext.HasVariable(name)) + var eventVarManager = Find.World.GetComponent(); + if (!eventVarManager.HasVariable(name)) { - EventContext.SetVariable(name, "0"); + eventVarManager.SetVariable(name, "0"); } - object variable = EventContext.GetVariable(name); + object variable = eventVarManager.GetVariable(name); string compareValue = value; if (!string.IsNullOrEmpty(valueVariableName)) { - compareValue = EventContext.GetVariable(valueVariableName)?.ToString(); + compareValue = eventVarManager.GetVariable(valueVariableName)?.ToString(); if (compareValue == null) { reason = $"Comparison variable '{valueVariableName}' not set."; diff --git a/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs b/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs index 5d9b56cf..295ff4d9 100644 --- a/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs +++ b/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using UnityEngine; using Verse; @@ -11,7 +12,7 @@ namespace WulaFallenEmpire private EventDef def; private Texture2D portrait; private Texture2D background; - private string selectedDescription; // Store the chosen description for this window instance + private string selectedDescription; private static EventUIConfigDef config; public static EventUIConfigDef Config @@ -34,7 +35,7 @@ namespace WulaFallenEmpire { return def.windowSize; } - return Config.defaultWindowSize; // Fallback to size from config + return Config.defaultWindowSize; } } @@ -45,22 +46,22 @@ namespace WulaFallenEmpire this.absorbInputAroundWindow = true; this.doCloseX = true; - // Select the description text + var eventVarManager = Find.World.GetComponent(); if (!def.descriptions.NullOrEmpty()) { if (def.descriptionMode == DescriptionSelectionMode.Random) { selectedDescription = def.descriptions.RandomElement(); } - else // Sequential + else { string indexVarName = $"_seq_desc_index_{def.defName}"; - int currentIndex = EventContext.GetVariable(indexVarName, 0); + int currentIndex = eventVarManager.GetVariable(indexVarName, 0); selectedDescription = def.descriptions[currentIndex]; int nextIndex = (currentIndex + 1) % def.descriptions.Count; - EventContext.SetVariable(indexVarName, nextIndex); + eventVarManager.SetVariable(indexVarName, nextIndex); } } else @@ -85,7 +86,6 @@ namespace WulaFallenEmpire HandleAction(def.immediateEffects); - // Append conditional descriptions if (!def.conditionalDescriptions.NullOrEmpty()) { foreach (var condDesc in def.conditionalDescriptions) @@ -97,20 +97,17 @@ namespace WulaFallenEmpire } } } - - // Format the description AFTER immediate effects have run and conditional text is appended + selectedDescription = FormatDescription(selectedDescription); } public override void DoWindowContents(Rect inRect) { - // 1. Draw Background if (background != null) { GUI.DrawTexture(inRect, background, ScaleMode.ScaleToFit); } - // 2. Draw Top-left defName and Label if (Config.showDefName) { Text.Font = GameFont.Tiny; @@ -123,10 +120,9 @@ namespace WulaFallenEmpire { Text.Font = Config.labelFont; Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label); - Text.Font = GameFont.Small; // Reset to default + Text.Font = GameFont.Small; } - // 3. Calculate Layout based on ConfigDef float virtualWidth = Config.lihuiSize.x + Config.textSize.x; float virtualHeight = Config.lihuiSize.y; @@ -147,8 +143,6 @@ namespace WulaFallenEmpire float startX = (inRect.width - totalContentWidth) / 2; float startY = (inRect.height - totalContentHeight) / 2; - // 4. Draw UI Elements - // lihui (Portrait) Rect lihuiRect = new Rect(startX, startY, scaledLihuiWidth, scaledLihuiHeight); if (portrait != null) { @@ -156,18 +150,13 @@ namespace WulaFallenEmpire } if (Config.drawBorders) { - GUI.color = Color.white; Widgets.DrawBox(lihuiRect); - GUI.color = Color.white; } - // name Rect nameRect = new Rect(lihuiRect.xMax, lihuiRect.y, scaledNameWidth, scaledNameHeight); if (Config.drawBorders) { - GUI.color = Color.white; Widgets.DrawBox(nameRect); - GUI.color = Color.white; } Text.Anchor = TextAnchor.MiddleCenter; Text.Font = GameFont.Medium; @@ -175,18 +164,14 @@ namespace WulaFallenEmpire Text.Font = GameFont.Small; Text.Anchor = TextAnchor.UpperLeft; - // text (Description) Rect textRect = new Rect(nameRect.x, nameRect.yMax + Config.textNameOffset * scale, scaledTextWidth, scaledTextHeight); if (Config.drawBorders) { - GUI.color = Color.white; Widgets.DrawBox(textRect); - GUI.color = Color.white; } Rect textInnerRect = textRect.ContractedBy(10f * scale); - Widgets.Label(textInnerRect, selectedDescription); // Use the selected description + Widgets.Label(textInnerRect, selectedDescription); - // option (Buttons) Rect optionRect = new Rect(nameRect.x, textRect.yMax + Config.optionsTextOffset * scale, scaledOptionsWidth, lihuiRect.height - nameRect.height - textRect.height - (Config.textNameOffset + Config.optionsTextOffset) * scale); Listing_Standard listing = new Listing_Standard(); @@ -209,7 +194,7 @@ namespace WulaFallenEmpire { if (option.hideWhenDisabled) { - continue; // Skip rendering this option entirely + continue; } Rect rect = listing.GetRect(30f); Widgets.ButtonText(rect, option.label, false, true, false); @@ -229,8 +214,7 @@ namespace WulaFallenEmpire foreach (var ce in conditionalEffects) { - string reason; - if (AreConditionsMet(ce.conditions, out reason)) + if (AreConditionsMet(ce.conditions, out _)) { if (!ce.effects.NullOrEmpty()) { @@ -276,14 +260,21 @@ namespace WulaFallenEmpire base.PostClose(); HandleAction(def.dismissEffects); } - private string FormatDescription(string description) - { - var variables = EventContext.GetAllVariables(); - foreach (var variable in variables) - { - description = description.Replace("{" + variable.Key + "}", variable.Value.ToString()); - } - return description; - } + + private string FormatDescription(string description) + { + var eventVarManager = Find.World.GetComponent(); + // Use regex to find all placeholders like {variableName} + return Regex.Replace(description, @"\{(.+?)\}", match => + { + string varName = match.Groups[1].Value; + if (eventVarManager.HasVariable(varName)) + { + // Important: GetVariable to get any type + return eventVarManager.GetVariable(varName)?.ToString() ?? ""; + } + return match.Value; // Keep placeholder if variable not found + }); + } } } diff --git a/Source/WulaFallenEmpire/EventSystem/Effect.cs b/Source/WulaFallenEmpire/EventSystem/Effect.cs index 7c926496..38a1ec24 100644 --- a/Source/WulaFallenEmpire/EventSystem/Effect.cs +++ b/Source/WulaFallenEmpire/EventSystem/Effect.cs @@ -8,7 +8,6 @@ namespace WulaFallenEmpire { public abstract class Effect { - // Allow the dialog to be null for contexts where there isn't one (like quests) public abstract void Execute(Dialog_CustomDisplay dialog = null); } @@ -44,7 +43,6 @@ namespace WulaFallenEmpire { if (nextDef.hiddenWindow) { - // Since effects are merged in PostLoad, we only need to execute dismissEffects here. if (!nextDef.dismissEffects.NullOrEmpty()) { foreach (var conditionalEffect in nextDef.dismissEffects) @@ -98,7 +96,6 @@ namespace WulaFallenEmpire { public override void Execute(Dialog_CustomDisplay dialog = null) { - // Only close the dialog if it exists dialog?.Close(); } } @@ -174,21 +171,20 @@ namespace WulaFallenEmpire public override void Execute(Dialog_CustomDisplay dialog = null) { - // Only set the variable if it doesn't already exist. - if (!EventContext.HasVariable(name)) + var eventVarManager = Find.World.GetComponent(); + if (!eventVarManager.HasVariable(name)) { - // Try to parse as int, then float, otherwise keep as string if (int.TryParse(value, out int intValue)) { - EventContext.SetVariable(name, intValue); + eventVarManager.SetVariable(name, intValue); } else if (float.TryParse(value, out float floatValue)) { - EventContext.SetVariable(name, floatValue); + eventVarManager.SetVariable(name, floatValue); } else { - EventContext.SetVariable(name, value); + eventVarManager.SetVariable(name, value); } } } @@ -214,7 +210,7 @@ namespace WulaFallenEmpire return; } - int goodwillChange = EventContext.GetVariable(goodwillVariableName); + int goodwillChange = Find.World.GetComponent().GetVariable(goodwillVariableName); Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null); } } @@ -238,6 +234,7 @@ namespace WulaFallenEmpire return; } + var eventVarManager = Find.World.GetComponent(); List spawnedPawns = new List(); for (int i = 0; i < count; i++) { @@ -249,11 +246,11 @@ namespace WulaFallenEmpire if (count == 1) { - EventContext.SetVariable(storeAs, spawnedPawns.First()); + eventVarManager.SetVariable(storeAs, spawnedPawns.First()); } else { - EventContext.SetVariable(storeAs, spawnedPawns); + eventVarManager.SetVariable(storeAs, spawnedPawns); } } } @@ -362,13 +359,15 @@ namespace WulaFallenEmpire Log.Error("[WulaFallenEmpire] Effect_ModifyVariable has a null or empty name."); return; } + + var eventVarManager = Find.World.GetComponent(); - if (!EventContext.HasVariable(name)) + if (!eventVarManager.HasVariable(name)) { - EventContext.SetVariable(name, 0f); + eventVarManager.SetVariable(name, 0f); } - float currentValue = EventContext.GetVariable(name); + float currentValue = eventVarManager.GetVariable(name); switch (operation) { @@ -396,7 +395,7 @@ namespace WulaFallenEmpire break; } - EventContext.SetVariable(name, currentValue); + eventVarManager.SetVariable(name, currentValue); } } @@ -411,7 +410,7 @@ namespace WulaFallenEmpire Log.Error("[WulaFallenEmpire] Effect_ClearVariable has a null or empty name."); return; } - EventContext.ClearVariable(name); + Find.World.GetComponent().ClearVariable(name); } } @@ -476,7 +475,6 @@ namespace WulaFallenEmpire return; } - // If custom pawn groups are defined, use them. if (!pawnGroupMakers.NullOrEmpty()) { IncidentParms parms = new IncidentParms @@ -502,102 +500,65 @@ namespace WulaFallenEmpire tile = map.Tile, points = this.points, faction = factionInst, + raidStrategy = this.raidStrategy, seed = parms.pawnGroupMakerSeed }; - - if (!pawnGroupMakers.TryRandomElement(out var chosenGroupMaker)) - { - Log.Error($"[WulaFallenEmpire] Effect_TriggerRaid could not find a suitable PawnGroupMaker for {points} points with groupKind {groupMakerParms.groupKind.defName} from the provided list."); - return; - } - - List pawns = chosenGroupMaker.GeneratePawns(groupMakerParms).ToList(); - if (!pawns.Any()) - { - Log.Error("[WulaFallenEmpire] Effect_TriggerRaid generated no pawns with the custom pawnGroupMakers."); - return; - } - - parms.raidArrivalMode.Worker.Arrive(pawns, parms); - - parms.raidStrategy.Worker.MakeLords(parms, pawns); - TaggedString finalLabel; - if (!string.IsNullOrEmpty(this.letterLabel)) + List pawns = PawnGroupMakerUtility.GeneratePawns(groupMakerParms).ToList(); + if (pawns.Any()) { - finalLabel = this.letterLabel; + raidArrivalMode.Worker.Arrive(pawns, parms); + if (!string.IsNullOrEmpty(letterLabel) && !string.IsNullOrEmpty(letterText)) + { + Find.LetterStack.ReceiveLetter(letterLabel, letterText, LetterDefOf.ThreatBig, pawns[0]); + } } - else - { - finalLabel = "LetterLabelRaid".Translate(factionInst.def.label).CapitalizeFirst(); - } - - TaggedString finalText; - if (!string.IsNullOrEmpty(this.letterText)) - { - finalText = this.letterText; - } - else - { - finalText = "LetterRaid".Translate( - factionInst.Name, - factionInst.def.pawnsPlural, - parms.raidStrategy.arrivalTextEnemy - ).CapitalizeFirst(); - } - - Pawn mostImportantPawn = pawns.FirstOrDefault(); - TargetInfo target = mostImportantPawn != null ? new TargetInfo(mostImportantPawn) : new TargetInfo(parms.spawnCenter, map); - - Find.LetterStack.ReceiveLetter(finalLabel, finalText, LetterDefOf.ThreatBig, target, factionInst); - } - else // Fallback to default raid incident worker - { - IncidentParms parms = new IncidentParms - { - target = map, - points = this.points, - faction = factionInst, - raidStrategy = this.raidStrategy, - raidArrivalMode = this.raidArrivalMode, - forced = true - }; - IncidentDefOf.RaidEnemy.Worker.TryExecute(parms); } } } - + public class Effect_CheckFactionGoodwill : Effect { public FactionDef factionDef; public string variableName; + public List successEffects; + public List failureEffects; public override void Execute(Dialog_CustomDisplay dialog = null) { if (factionDef == null) { - Log.Error("Effect_CheckFactionGoodwill requires a factionDef."); - return; - } - if (string.IsNullOrEmpty(variableName)) - { - Log.Error("Effect_CheckFactionGoodwill requires a variableName."); + Log.Error("[WulaFallenEmpire] Effect_CheckFactionGoodwill has a null faction Def."); return; } - Faction faction = Find.FactionManager.FirstFactionOfDef(factionDef); - if (faction == null) + Faction targetFaction = Find.FactionManager.FirstFactionOfDef(factionDef); + if (targetFaction == null) { - // Faction doesn't exist, store a default value (e.g., 0 or a specific marker) - EventContext.SetVariable(variableName, 0); - Log.Warning($"Faction with def {factionDef.defName} not found. Setting '{variableName}' to 0."); + Log.Warning($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{factionDef.defName}'."); + ExecuteEffects(failureEffects, dialog); return; } - int goodwill = faction.GoodwillWith(Faction.OfPlayer); - EventContext.SetVariable(variableName, goodwill); + int requiredGoodwill = Find.World.GetComponent().GetVariable(variableName); + int currentGoodwill = Faction.OfPlayer.GoodwillWith(targetFaction); + if (currentGoodwill >= requiredGoodwill) + { + ExecuteEffects(successEffects, dialog); + } + else + { + ExecuteEffects(failureEffects, dialog); + } + } + + private void ExecuteEffects(List effects, Dialog_CustomDisplay dialog) + { + if (effects.NullOrEmpty()) return; + foreach (var effect in effects) + { + effect.Execute(dialog); + } } } - } - - +} diff --git a/Source/WulaFallenEmpire/EventSystem/EventContext.cs b/Source/WulaFallenEmpire/EventSystem/EventContext.cs deleted file mode 100644 index 5760f2cf..00000000 --- a/Source/WulaFallenEmpire/EventSystem/EventContext.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using Verse; - -namespace WulaFallenEmpire -{ - public static class EventContext - { - private static Dictionary variables = new Dictionary(); - - public static void SetVariable(string name, object value) - { - if (variables.ContainsKey(name)) - { - variables[name] = value; - } - else - { - variables.Add(name, value); - } - Log.Message($"[EventContext] Set variable '{name}' to '{value}'."); - } - - public static T GetVariable(string name, T defaultValue = default) - { - if (variables.TryGetValue(name, out object value)) - { - if (value is T typedValue) - { - return typedValue; - } - // Try to convert, e.g., from int to float - try - { - return (T)System.Convert.ChangeType(value, typeof(T)); - } - catch (System.Exception) - { - Log.Warning($"[EventContext] Variable '{name}' is of type {value.GetType()} but could not be converted to {typeof(T)}."); - return defaultValue; - } - } - Log.Warning($"[EventContext] Variable '{name}' not found. Returning default value."); - return defaultValue; - } - - public static bool HasVariable(string name) - { - return variables.ContainsKey(name); - } - - public static Dictionary GetAllVariables() - { - return new Dictionary(variables); - } - - public static void Clear() - { - variables.Clear(); - Log.Message("[EventContext] All variables cleared."); - } - - public static void ClearVariable(string name) - { - if (variables.Remove(name)) - { - Log.Message($"[EventContext] Cleared variable '{name}'."); - } - else - { - Log.Warning($"[EventContext] Tried to clear variable '{name}' but it was not found."); - } - } - } -} diff --git a/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs b/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs new file mode 100644 index 00000000..acfc0be4 --- /dev/null +++ b/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs @@ -0,0 +1,156 @@ +using System.Collections.Generic; +using Verse; +using RimWorld; +using RimWorld.Planet; + +namespace WulaFallenEmpire +{ + public class EventVariableManager : WorldComponent + { + private Dictionary intVars = new Dictionary(); + private Dictionary floatVars = new Dictionary(); + private Dictionary stringVars = new Dictionary(); + private Dictionary pawnVars = new Dictionary(); + private Dictionary> pawnListVars = new Dictionary>(); + + // Required for WorldComponent + public EventVariableManager(World world) : base(world) + { + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Collections.Look(ref intVars, "intVars", LookMode.Value, LookMode.Value); + Scribe_Collections.Look(ref floatVars, "floatVars", LookMode.Value, LookMode.Value); + Scribe_Collections.Look(ref stringVars, "stringVars", LookMode.Value, LookMode.Value); + Scribe_Collections.Look(ref pawnVars, "pawnVars", LookMode.Value, LookMode.Reference); + Scribe_Collections.Look(ref pawnListVars, "pawnListVars", LookMode.Value, LookMode.Reference); + + // Ensure dictionaries are not null after loading + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + intVars ??= new Dictionary(); + floatVars ??= new Dictionary(); + stringVars ??= new Dictionary(); + pawnVars ??= new Dictionary(); + pawnListVars ??= new Dictionary>(); + } + } + + public void SetVariable(string name, object value) + { + if (string.IsNullOrEmpty(name)) return; + + // Clear any existing variable with the same name to prevent type confusion + ClearVariable(name); + + if (value is int intValue) + { + intVars[name] = intValue; + } + else if (value is float floatValue) + { + floatVars[name] = floatValue; + } + else if (value is string stringValue) + { + stringVars[name] = stringValue; + } + else if (value is Pawn pawnValue) + { + pawnVars[name] = pawnValue; + } + else if (value is List pawnListValue) + { + pawnListVars[name] = pawnListValue; + } + else if (value != null) + { + stringVars[name] = value.ToString(); + Log.Warning($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} was converted to string for storage. This may lead to unexpected behavior."); + } + } + + public T GetVariable(string name, T defaultValue = default) + { + if (string.IsNullOrEmpty(name)) return defaultValue; + + object value = null; + bool found = false; + + if (typeof(T) == typeof(List) && pawnListVars.TryGetValue(name, out var pawnListVal)) + { + value = pawnListVal; + found = true; + } + else if (typeof(T) == typeof(Pawn) && pawnVars.TryGetValue(name, out var pawnVal)) + { + value = pawnVal; + found = true; + } + else if (typeof(T) == typeof(float) && floatVars.TryGetValue(name, out var floatVal)) + { + value = floatVal; + found = true; + } + else if (typeof(T) == typeof(int) && intVars.TryGetValue(name, out var intVal)) + { + value = intVal; + found = true; + } + else if (stringVars.TryGetValue(name, out var stringVal)) + { + value = stringVal; + found = true; + } + + if (found) + { + if (value is T typedValue) + { + return typedValue; + } + + try + { + return (T)System.Convert.ChangeType(value, typeof(T)); + } + catch (System.Exception) + { + Log.Warning($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} could not be converted to {typeof(T)}."); + return defaultValue; + } + } + + return defaultValue; + } + + public bool HasVariable(string name) + { + return intVars.ContainsKey(name) || + floatVars.ContainsKey(name) || + stringVars.ContainsKey(name) || + pawnVars.ContainsKey(name) || + pawnListVars.ContainsKey(name); + } + + public void ClearVariable(string name) + { + intVars.Remove(name); + floatVars.Remove(name); + stringVars.Remove(name); + pawnVars.Remove(name); + pawnListVars.Remove(name); + } + + public void ClearAll() + { + intVars.Clear(); + floatVars.Clear(); + stringVars.Clear(); + pawnVars.Clear(); + pawnListVars.Clear(); + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 1aaa0e90..9c7711df 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -86,7 +86,7 @@ - +