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; } } // 新增:自定义按钮样式设置 private static readonly Color CustomButtonNormalColor = new Color(0.5f, 0.2f, 0.2f, 1f); private static readonly Color CustomButtonHoverColor = new Color(0.6f, 0.3f, 0.3f, 1f); private static readonly Color CustomButtonDisabledColor = new Color(0.15f, 0.15f, 0.15f, 0.6f); private static readonly Color CustomButtonTextNormalColor = new Color(0.9f, 0.9f, 0.9f, 1f); private static readonly Color CustomButtonTextHoverColor = new Color(1f, 1f, 1f, 1f); private static readonly Color CustomButtonTextDisabledColor = new Color(0.6f, 0.6f, 0.6f, 1f); // 绘制单个选项 - 使用自定义样式 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); // 保存原始状态 Color originalColor = GUI.color; GameFont originalFont = Text.Font; Color originalTextColor = GUI.contentColor; TextAnchor originalAnchor = Text.Anchor; try { // 设置文本居中 Text.Anchor = TextAnchor.MiddleCenter; Text.Font = GameFont.Small; if (conditionsMet) { // 启用状态的选项 - 使用自定义样式 if (option.useCustomColors) { // 使用选项自定义颜色 DrawCustomButtonWithColors(optionRect, option.label.Translate(), option); } else { // 使用默认自定义颜色 DrawCustomButton(optionRect, option.label.Translate(), isEnabled: true); } // 添加点击处理 if (Widgets.ButtonInvisible(optionRect)) { HandleAction(option.optionEffects); } } else { // 禁用状态的选项 - 使用自定义禁用样式 if (option.useCustomColors && option.disabledColor.HasValue) { // 使用选项自定义禁用颜色 DrawCustomButtonWithColors(optionRect, option.label.Translate(), option, isEnabled: false); } else { // 使用默认自定义禁用颜色 DrawCustomButton(optionRect, option.label.Translate(), isEnabled: false); } // 添加禁用提示 TooltipHandler.TipRegion(optionRect, GetDisabledReason(option, reason).Translate()); } } finally { // 恢复原始状态 GUI.color = originalColor; Text.Font = originalFont; GUI.contentColor = originalTextColor; Text.Anchor = originalAnchor; } } /// /// 绘制自定义按钮(基础版本) /// private void DrawCustomButton(Rect rect, string label, bool isEnabled = true) { bool isMouseOver = Mouse.IsOver(rect); // 确定按钮状态颜色 Color buttonColor, textColor; if (!isEnabled) { // 禁用状态 buttonColor = CustomButtonDisabledColor; textColor = CustomButtonTextDisabledColor; } else if (isMouseOver) { // 悬停状态 buttonColor = CustomButtonHoverColor; textColor = CustomButtonTextHoverColor; } else { // 正常状态 buttonColor = CustomButtonNormalColor; textColor = CustomButtonTextNormalColor; } // 绘制按钮背景 GUI.color = buttonColor; Widgets.DrawBoxSolid(rect, buttonColor); // 绘制边框 if (isEnabled) { Widgets.DrawBox(rect, 1); } else { // 禁用状态的边框更细更暗 Widgets.DrawBox(rect, 1); } // 绘制文本 GUI.color = textColor; Text.Anchor = TextAnchor.MiddleCenter; Widgets.Label(rect.ContractedBy(4f), label); // 如果是禁用状态,添加删除线效果 if (!isEnabled) { GUI.color = new Color(0.6f, 0.6f, 0.6f, 0.8f); Widgets.DrawLine( new Vector2(rect.x + 10f, rect.center.y), new Vector2(rect.xMax - 10f, rect.center.y), GUI.color, 1f ); } } /// /// 绘制自定义按钮(使用选项自定义颜色) /// private void DrawCustomButtonWithColors(Rect rect, string label, EventOption option, bool isEnabled = true) { bool isMouseOver = Mouse.IsOver(rect); // 确定按钮状态颜色 Color buttonColor, textColor; if (!isEnabled) { // 禁用状态 buttonColor = option.disabledColor ?? CustomButtonDisabledColor; textColor = option.textDisabledColor ?? CustomButtonTextDisabledColor; } else if (isMouseOver) { // 悬停状态 buttonColor = option.hoverColor ?? CustomButtonHoverColor; textColor = option.textHoverColor ?? CustomButtonTextHoverColor; } else { // 正常状态 buttonColor = option.normalColor ?? CustomButtonNormalColor; textColor = option.textColor ?? CustomButtonTextNormalColor; } // 绘制按钮背景 GUI.color = buttonColor; Widgets.DrawBoxSolid(rect, buttonColor); // 绘制边框 Widgets.DrawBox(rect); // 绘制文本 GUI.color = textColor; Text.Anchor = TextAnchor.MiddleCenter; Widgets.Label(rect.ContractedBy(4f), label); // 如果是禁用状态,添加删除线效果 if (!isEnabled) { GUI.color = new Color(0.6f, 0.6f, 0.6f, 0.8f); Widgets.DrawLine( new Vector2(rect.x + 10f, rect.center.y), new Vector2(rect.xMax - 10f, rect.center.y), GUI.color, 1f ); } } // 使用配置的窗口尺寸 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().Translate(); } else { string indexVarName = $"_seq_desc_index_{def.defName}"; int currentIndex = eventVarManager.GetVariable(indexVarName, 0); selectedDescription = def.descriptions[currentIndex].Translate(); 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.Translate(); } } } 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.Translate()); 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.Translate()); 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 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.Translate(); } 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; }); } } }