using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEngine; using Verse; namespace WulaFallenEmpire { public class Dialog_CustomDisplay : Window { private EventDef def; private Texture2D portrait; private Texture2D background; private string selectedDescription; private static EventUIConfigDef config; public static EventUIConfigDef Config { get { if (config == null) { config = DefDatabase.GetNamed("Wula_EventUIConfig"); } return config; } } // 使用配置的窗口尺寸 public override Vector2 InitialSize { get { return def.windowSize != Vector2.zero ? def.windowSize : Config.windowSize; } } public Dialog_CustomDisplay(EventDef def) { this.def = def; // 关键修改:使用配置控制是否暂停游戏 this.forcePause = Config.pauseGameOnOpen; this.absorbInputAroundWindow = true; this.doCloseX = true; // 根据配置设置是否绘制窗口背景和阴影 this.doWindowBackground = Config.showMainWindow; this.drawShadow = Config.showMainWindow; var eventVarManager = Find.World.GetComponent(); if (!def.descriptions.NullOrEmpty()) { if (def.descriptionMode == DescriptionSelectionMode.Random) { selectedDescription = def.descriptions.RandomElement(); } else { string indexVarName = $"_seq_desc_index_{def.defName}"; int currentIndex = eventVarManager.GetVariable(indexVarName, 0); selectedDescription = def.descriptions[currentIndex]; int nextIndex = (currentIndex + 1) % def.descriptions.Count; eventVarManager.SetVariable(indexVarName, nextIndex); } } else { selectedDescription = "Error: No descriptions found in def."; } } public override void PreOpen() { base.PreOpen(); // 加载立绘 if (Config.showPortrait && !def.portraitPath.NullOrEmpty()) { portrait = ContentFinder.Get(def.portraitPath); } // 加载背景 - 优先级:事件定义背景 > 自定义背景 > 默认背景 string bgPath = null; // 1. 首先检查事件定义中的背景 if (!def.backgroundImagePath.NullOrEmpty()) { bgPath = def.backgroundImagePath; } // 2. 然后检查自定义背景 else if (!string.IsNullOrEmpty(Config.customBackgroundImagePath)) { bgPath = Config.customBackgroundImagePath; } // 3. 最后检查是否使用默认背景 else if (Config.useDefaultBackground) { // 这里可以设置一个默认背景路径,或者留空 // bgPath = "UI/Backgrounds/DefaultEventBackground"; } if (!bgPath.NullOrEmpty()) { background = ContentFinder.Get(bgPath); } HandleAction(def.immediateEffects); if (!def.conditionalDescriptions.NullOrEmpty()) { foreach (var condDesc in def.conditionalDescriptions) { string reason; if (AreConditionsMet(condDesc.conditions, out reason)) { selectedDescription += "\n\n" + condDesc.text; } } } selectedDescription = FormatDescription(selectedDescription); } public override void DoWindowContents(Rect inRect) { // 绘制自定义背景(如果有) if (background != null) { GUI.DrawTexture(inRect, background, ScaleMode.StretchToFill); } float currentY = 0f; // 1. 立绘 if (Config.showPortrait) { currentY += Config.GetScaledMargin(Config.portraitMargins.x, inRect); Rect portraitRect = Config.GetScaledRect(Config.portraitSize, inRect); portraitRect.y = currentY; if (portrait != null) { // 保持图片比例 float aspectRatio = (float)portrait.width / portrait.height; float portraitWidth = portraitRect.height * aspectRatio; // 居中显示 Rect centeredPortraitRect = new Rect( portraitRect.center.x - portraitWidth / 2, portraitRect.y, portraitWidth, portraitRect.height ); GUI.DrawTexture(centeredPortraitRect, portrait, ScaleMode.ScaleToFit); } if (Config.drawBorders) { Widgets.DrawBox(portraitRect); } currentY += portraitRect.height + Config.GetScaledMargin(Config.portraitMargins.y, inRect); } // 2. Label if (Config.showLabel) { currentY += Config.GetScaledMargin(Config.labelMargins.x, inRect); Rect labelRect = Config.GetScaledRect(Config.labelSize, inRect); labelRect.y = currentY; Text.Anchor = TextAnchor.MiddleCenter; Text.Font = Config.labelFont; Widgets.Label(labelRect, def.label); Text.Font = GameFont.Small; Text.Anchor = TextAnchor.UpperLeft; if (Config.drawBorders) { Widgets.DrawBox(labelRect); } currentY += labelRect.height + Config.GetScaledMargin(Config.labelMargins.y, inRect); } // 3. CharacterName if (Config.showCharacterName) { currentY += Config.GetScaledMargin(Config.characterNameMargins.x, inRect); Rect nameRect = Config.GetScaledRect(Config.characterNameSize, inRect); nameRect.y = currentY; Text.Anchor = TextAnchor.MiddleCenter; Text.Font = GameFont.Medium; Widgets.Label(nameRect, def.characterName); Text.Font = GameFont.Small; Text.Anchor = TextAnchor.UpperLeft; if (Config.drawBorders) { Widgets.DrawBox(nameRect); } currentY += nameRect.height + Config.GetScaledMargin(Config.characterNameMargins.y, inRect); } // 4. 描述 if (Config.showDescriptions) { currentY += Config.GetScaledMargin(Config.descriptionsMargins.x, inRect); Rect descriptionRect = Config.GetScaledRect(Config.descriptionsSize, inRect); descriptionRect.y = currentY; if (Config.drawBorders) { Widgets.DrawBox(descriptionRect); } // 应用描述区域内边距 Vector2 scaledDescriptionsPadding = Config.GetScaledDescriptionsPadding(descriptionRect); Rect descriptionInnerRect = descriptionRect.ContractedBy(scaledDescriptionsPadding.y, scaledDescriptionsPadding.x); // 使用可滚动的文本区域 float textHeight = Text.CalcHeight(selectedDescription, descriptionInnerRect.width); Rect viewRect = new Rect(0, 0, descriptionInnerRect.width, Mathf.Max(textHeight, descriptionInnerRect.height)); Widgets.BeginScrollView(descriptionInnerRect, ref descriptionScrollPosition, viewRect); Widgets.Label(new Rect(0, 0, viewRect.width, viewRect.height), selectedDescription); Widgets.EndScrollView(); currentY += descriptionRect.height + Config.GetScaledMargin(Config.descriptionsMargins.y, inRect); } // 5. 选项列表 if (Config.showOptions) { currentY += Config.GetScaledMargin(Config.optionsListMargins.x, inRect); Rect optionsRect = Config.GetScaledRect(Config.optionsListSize, inRect); optionsRect.y = currentY; if (Config.drawBorders) { Widgets.DrawBox(optionsRect); } DrawOptions(optionsRect, def.options); currentY += optionsRect.height + Config.GetScaledMargin(Config.optionsListMargins.y, inRect); } // 调试信息 if (Config.showDefName) { Text.Font = GameFont.Tiny; GUI.color = Color.gray; Widgets.Label(new Rect(5, 5, inRect.width - 10, 20f), def.defName); GUI.color = Color.white; } } // 滚动位置 private Vector2 descriptionScrollPosition = Vector2.zero; private Vector2 optionsScrollPosition = Vector2.zero; // 绘制选项区域 private void DrawOptions(Rect rect, List options) { if (options == null || options.Count == 0) return; // 应用选项列表内边距 Vector2 scaledPadding = Config.GetScaledOptionsListPadding(rect); Rect optionsInnerRect = rect.ContractedBy(scaledPadding.x, scaledPadding.y); // 计算缩放后的选项尺寸和间距 Vector2 scaledOptionSize = Config.GetScaledOptionSize(optionsInnerRect); float scaledOptionSpacing = Config.GetScaledOptionSpacing(optionsInnerRect); // 计算可见的选项 var visibleOptions = new List(); var eventVarManager = Find.World.GetComponent(); foreach (var option in options) { string reason; bool conditionsMet = AreConditionsMet(option.conditions, out reason); if (!conditionsMet && option.hideWhenDisabled) { continue; } visibleOptions.Add(option); } if (visibleOptions.Count == 0) return; // 计算选项列表的总高度 float totalOptionsHeight = (scaledOptionSize.y * visibleOptions.Count) + (scaledOptionSpacing * (visibleOptions.Count - 1)); bool needsScroll = totalOptionsHeight > optionsInnerRect.height; // 如果需要滚动,使用滚动视图 if (needsScroll) { Rect viewRect = new Rect(0, 0, optionsInnerRect.width - 20f, totalOptionsHeight); Widgets.BeginScrollView(optionsInnerRect, ref optionsScrollPosition, viewRect); float currentY = 0f; foreach (var option in visibleOptions) { DrawSingleOption(new Rect(0, currentY, viewRect.width, scaledOptionSize.y), option); currentY += scaledOptionSize.y + scaledOptionSpacing; } Widgets.EndScrollView(); } else { // 不需要滚动,垂直居中显示所有选项 float totalHeight = (scaledOptionSize.y * visibleOptions.Count) + (scaledOptionSpacing * (visibleOptions.Count - 1)); float startY = optionsInnerRect.y + (optionsInnerRect.height - totalHeight) / 2; float currentY = startY; foreach (var option in visibleOptions) { DrawSingleOption(new Rect(optionsInnerRect.x, currentY, optionsInnerRect.width, scaledOptionSize.y), option); currentY += scaledOptionSize.y + scaledOptionSpacing; } } } // 绘制单个选项 private void DrawSingleOption(Rect rect, EventOption option) { string reason; bool conditionsMet = AreConditionsMet(option.conditions, out reason); // 水平居中选项 float optionWidth = Mathf.Min(rect.width, Config.optionSize.x * (rect.width / Config.windowSize.x)); float optionX = rect.x + (rect.width - optionWidth) / 2; Rect optionRect = new Rect(optionX, rect.y, optionWidth, rect.height); if (conditionsMet) { // 保存原始颜色状态 Color originalColor = GUI.color; GameFont originalFont = Text.Font; Color originalTextColor = GUI.contentColor; try { // 应用自定义颜色 if (option.useCustomColors) { ApplyOptionColors(option, optionRect); } if (Widgets.ButtonText(optionRect, option.label)) { HandleAction(option.optionEffects); } } finally { // 恢复原始颜色状态 GUI.color = originalColor; Text.Font = originalFont; GUI.contentColor = originalTextColor; } } else { // 禁用状态的选项 Color originalColor = GUI.color; GameFont originalFont = Text.Font; Color originalTextColor = GUI.contentColor; try { // 应用禁用状态的自定义颜色 if (option.useCustomColors && option.disabledColor.HasValue) { GUI.color = option.disabledColor.Value; } if (option.useCustomColors && option.textDisabledColor.HasValue) { GUI.contentColor = option.textDisabledColor.Value; } Widgets.ButtonText(optionRect, option.label, false, true, false); TooltipHandler.TipRegion(optionRect, GetDisabledReason(option, reason)); } finally { // 恢复原始颜色状态 GUI.color = originalColor; Text.Font = originalFont; GUI.contentColor = originalTextColor; } } } // 应用选项颜色 private void ApplyOptionColors(EventOption option, Rect rect) { if (!option.useCustomColors) return; // 检查鼠标是否悬停在选项上 bool isMouseOver = Mouse.IsOver(rect); // 设置按钮背景颜色 if (isMouseOver && option.hoverColor.HasValue) { GUI.color = option.hoverColor.Value; } else if (option.normalColor.HasValue) { GUI.color = option.normalColor.Value; } // 设置文本颜色 if (isMouseOver && option.textHoverColor.HasValue) { GUI.contentColor = option.textHoverColor.Value; } else if (option.textColor.HasValue) { GUI.contentColor = option.textColor.Value; } } private void HandleAction(List conditionalEffects) { if (conditionalEffects.NullOrEmpty()) { return; } foreach (var ce in conditionalEffects) { if (AreConditionsMet(ce.conditions, out _)) { ce.Execute(this); } } } private bool AreConditionsMet(List conditions, out string reason) { reason = ""; if (conditions.NullOrEmpty()) { return true; } foreach (var condition in conditions) { if (!condition.IsMet(out string singleReason)) { reason = singleReason; return false; } } return true; } private string GetDisabledReason(EventOption option, string reason) { if (!option.disabledReason.NullOrEmpty()) { return option.disabledReason; } return reason; } public override void PostClose() { base.PostClose(); HandleAction(def.dismissEffects); } private string FormatDescription(string description) { var eventVarManager = Find.World.GetComponent(); return Regex.Replace(description, @"\{(.+?)\}", match => { string varName = match.Groups[1].Value; if (eventVarManager.HasVariable(varName)) { return eventVarManager.GetVariable(varName)?.ToString() ?? ""; } return match.Value; }); } } }