feat(WulaFallenEmpire): 新增自定义 UI 布局并优化事件系统
- 添加新布局配置和相关代码,支持自定义 UI 样式 - 实现新的事件定义和对话选项,增加游戏互动性 - 优化事件处理逻辑,提高代码复用性和可维护性 - 更新事件配置文件,引入新布局参数
This commit is contained in:
Binary file not shown.
@@ -1,6 +1,57 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<Defs>
|
<Defs>
|
||||||
|
|
||||||
|
<WulaFallenEmpire.EventDef>
|
||||||
|
<defName>Wula_UI_Anisia_1_NewWindow</defName>
|
||||||
|
<label>来自守密者的问候</label>
|
||||||
|
<portraitPath>Wula/Events/Portraits/WULA_Anisia_1</portraitPath>
|
||||||
|
<characterName>URa-1138「艾妮西娅」</characterName>
|
||||||
|
<windowType>WulaFallenEmpire.Dialog_NewLayoutDisplay</windowType>
|
||||||
|
<descriptions>
|
||||||
|
<li>很高兴看到你们的殖民地没有变成荒野中的烂泥。那么,今天找我有什么事情?</li>
|
||||||
|
<li>宇宙生存法则第一条:不要惹平胸火气大的女人。</li>
|
||||||
|
<li>什么样的结局,才配得上这一路的颠沛流离?无论你们走向何方,我都将见证你们。</li>
|
||||||
|
</descriptions>
|
||||||
|
<options>
|
||||||
|
<li>
|
||||||
|
<label>我想问你点问题</label>
|
||||||
|
<optionEffects>
|
||||||
|
<li>
|
||||||
|
<effects>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_OpenCustomUI">
|
||||||
|
<defName>Wula_UI_Anisia_10</defName>
|
||||||
|
</li>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_CloseDialog" />
|
||||||
|
</effects>
|
||||||
|
</li>
|
||||||
|
</optionEffects>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>有事情想拜托你</label>
|
||||||
|
<optionEffects>
|
||||||
|
<li>
|
||||||
|
<effects>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_OpenCustomUI">
|
||||||
|
<defName>Wula_UI_Anisia_200</defName>
|
||||||
|
</li>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_CloseDialog" />
|
||||||
|
</effects>
|
||||||
|
</li>
|
||||||
|
</optionEffects>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>再见</label>
|
||||||
|
<optionEffects>
|
||||||
|
<li>
|
||||||
|
<effects>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_CloseDialog" />
|
||||||
|
</effects>
|
||||||
|
</li>
|
||||||
|
</optionEffects>
|
||||||
|
</li>
|
||||||
|
</options>
|
||||||
|
</WulaFallenEmpire.EventDef>
|
||||||
|
|
||||||
<WulaFallenEmpire.EventDef>
|
<WulaFallenEmpire.EventDef>
|
||||||
<defName>Wula_Test_Raid_Event</defName>
|
<defName>Wula_Test_Raid_Event</defName>
|
||||||
<label>测试袭击事件</label>
|
<label>测试袭击事件</label>
|
||||||
|
|||||||
@@ -22,6 +22,15 @@
|
|||||||
<optionsTextOffset>0</optionsTextOffset>
|
<optionsTextOffset>0</optionsTextOffset>
|
||||||
|
|
||||||
<defaultWindowSize>(750, 600)</defaultWindowSize>
|
<defaultWindowSize>(750, 600)</defaultWindowSize>
|
||||||
|
|
||||||
|
<!-- New Layout Dimensions -->
|
||||||
|
<newLayoutNameSize>(200, 50)</newLayoutNameSize>
|
||||||
|
<newLayoutLihuiSize>(600, 200)</newLayoutLihuiSize>
|
||||||
|
<newLayoutTextSize>(600, 200)</newLayoutTextSize>
|
||||||
|
<newLayoutOptionsWidth>600</newLayoutOptionsWidth>
|
||||||
|
<newLayoutPadding>20</newLayoutPadding>
|
||||||
|
<newLayoutTextNameOffset>20</newLayoutTextNameOffset>
|
||||||
|
<newLayoutOptionsTextOffset>20</newLayoutOptionsTextOffset>
|
||||||
|
|
||||||
</WulaFallenEmpire.EventUIConfigDef>
|
</WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
|
||||||
|
|||||||
178
Source/Documentation/new_layout_preview.html
Normal file
178
Source/Documentation/new_layout_preview.html
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>事件UI布局预览 (动态版)</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 1000px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
background-color: #222;
|
||||||
|
color: #ddd;
|
||||||
|
border: 1px solid #555;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.window {
|
||||||
|
width: 1000px;
|
||||||
|
height: 750px;
|
||||||
|
background-color: #555;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.element {
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 2px solid white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 1px 1px 2px black;
|
||||||
|
}
|
||||||
|
.lihui { background-color: rgba(255, 0, 0, 0.4); }
|
||||||
|
.name { background-color: rgba(0, 255, 0, 0.4); }
|
||||||
|
.text { background-color: rgba(0, 0, 255, 0.4); }
|
||||||
|
.options { background-color: rgba(255, 255, 0, 0.4); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="controls">
|
||||||
|
<h3>动态布局预览</h3>
|
||||||
|
<p>请将您的 <code>EventUIConfig.xml</code> 文件内容完整粘贴到下面的文本框中,然后点击“生成预览”按钮。</p>
|
||||||
|
<textarea id="xmlInput" placeholder="在这里粘贴 EventUIConfig.xml 的内容..."></textarea>
|
||||||
|
<button onclick="generatePreview()">生成预览</button>
|
||||||
|
</div>
|
||||||
|
<div class="window" id="window">
|
||||||
|
<!-- 布局将在这里生成 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function parseVector2(str) {
|
||||||
|
const match = str.match(/\((\s*[\d.]+)\s*,\s*([\d.]+)\s*\)/);
|
||||||
|
return match ? { x: parseFloat(match[1]), y: parseFloat(match[2]) } : { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function generatePreview() {
|
||||||
|
const xmlString = document.getElementById('xmlInput').value;
|
||||||
|
if (!xmlString) {
|
||||||
|
alert('请先粘贴XML内容!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
|
||||||
|
|
||||||
|
// Need to escape the dot in the class name for querySelector
|
||||||
|
const configDef = xmlDoc.querySelector('WulaFallenEmpire\\.EventUIConfigDef');
|
||||||
|
if (!configDef) {
|
||||||
|
alert('无法找到 WulaFallenEmpire.EventUIConfigDef 节点,请检查XML内容是否正确。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
newLayoutNameSize: parseVector2(configDef.querySelector('newLayoutNameSize')?.textContent || '(0,0)'),
|
||||||
|
newLayoutLihuiSize: parseVector2(configDef.querySelector('newLayoutLihuiSize')?.textContent || '(0,0)'),
|
||||||
|
newLayoutTextSize: parseVector2(configDef.querySelector('newLayoutTextSize')?.textContent || '(0,0)'),
|
||||||
|
newLayoutOptionsWidth: parseFloat(configDef.querySelector('newLayoutOptionsWidth')?.textContent || '0'),
|
||||||
|
newLayoutPadding: parseFloat(configDef.querySelector('newLayoutPadding')?.textContent || '0'),
|
||||||
|
newLayoutTextNameOffset: parseFloat(configDef.querySelector('newLayoutTextNameOffset')?.textContent || '0'),
|
||||||
|
newLayoutOptionsTextOffset: parseFloat(configDef.querySelector('newLayoutOptionsTextOffset')?.textContent || '0')
|
||||||
|
};
|
||||||
|
|
||||||
|
const windowRect = { width: 1000, height: 750 };
|
||||||
|
const windowDiv = document.getElementById('window');
|
||||||
|
windowDiv.innerHTML = ''; // Clear previous preview
|
||||||
|
|
||||||
|
// --- Calculation logic from Dialog_NewLayoutDisplay.cs ---
|
||||||
|
const padding = config.newLayoutPadding;
|
||||||
|
|
||||||
|
// Name
|
||||||
|
const nameHeight = config.newLayoutNameSize.y;
|
||||||
|
const nameWidth = config.newLayoutNameSize.x;
|
||||||
|
const nameRect = { left: (windowRect.width - nameWidth) / 2, top: padding, width: nameWidth, height: nameHeight };
|
||||||
|
createDiv('name', '名称 (Name)', nameRect);
|
||||||
|
|
||||||
|
// Lihui (Portrait)
|
||||||
|
const lihuiWidth = config.newLayoutLihuiSize.x;
|
||||||
|
const lihuiHeight = config.newLayoutLihuiSize.y;
|
||||||
|
const lihuiRect = { left: (windowRect.width - lihuiWidth) / 2, top: nameRect.top + nameRect.height + padding, width: lihuiWidth, height: lihuiHeight };
|
||||||
|
createDiv('lihui', '立绘 (Portrait)', lihuiRect);
|
||||||
|
|
||||||
|
// Options (pre-calculate height for text area)
|
||||||
|
const optionButtonHeight = 30; // This is a placeholder, as JS can't directly use C#'s dynamic calculation
|
||||||
|
const optionSpacing = 5;
|
||||||
|
let calculatedOptionHeight = 100; // Default or minimum height for options for preview
|
||||||
|
// In a real JS implementation, you might dynamically measure the height needed for buttons based on text content
|
||||||
|
|
||||||
|
const optionsWidth = config.newLayoutOptionsWidth;
|
||||||
|
const optionRect = { left: (windowRect.width - optionsWidth) / 2, top: windowRect.height - padding - calculatedOptionHeight, width: optionsWidth, height: calculatedOptionHeight };
|
||||||
|
|
||||||
|
// Text (Description)
|
||||||
|
const textWidth = config.newLayoutTextSize.x;
|
||||||
|
const textRect = { left: (windowRect.width - textWidth) / 2, top: lihuiRect.top + lihuiRect.height + padding, width: textWidth, height: optionRect.top - (lihuiRect.top + lihuiRect.height + padding) - padding };
|
||||||
|
createDiv('text', '描述 (Description)', textRect);
|
||||||
|
|
||||||
|
createDiv('options', '选项 (Options)', optionRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiv(className, text, rect) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = `element ${className}`;
|
||||||
|
div.textContent = text;
|
||||||
|
div.style.left = `${rect.left}px`;
|
||||||
|
div.style.top = `${rect.top}px`;
|
||||||
|
div.style.width = `${rect.width}px`;
|
||||||
|
div.style.height = `${rect.height}px`;
|
||||||
|
document.getElementById('window').appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-populate with example content
|
||||||
|
document.getElementById('xmlInput').value = `<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
<WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
<defName>Wula_EventUIConfig</defName>
|
||||||
|
|
||||||
|
<!-- General Style -->
|
||||||
|
<labelFont>Small</labelFont>
|
||||||
|
<drawBorders>true</drawBorders>
|
||||||
|
<defaultBackgroundImagePath></defaultBackgroundImagePath>
|
||||||
|
|
||||||
|
<!-- New Layout Dimensions -->
|
||||||
|
<newLayoutNameSize>(200, 50)</newLayoutNameSize>
|
||||||
|
<newLayoutLihuiSize>(300, 400)</newLayoutLihuiSize>
|
||||||
|
<newLayoutTextSize>(600, 200)</newLayoutTextSize>
|
||||||
|
<newLayoutOptionsWidth>600</newLayoutOptionsWidth>
|
||||||
|
<newLayoutPadding>20</newLayoutPadding>
|
||||||
|
<newLayoutTextNameOffset>20</newLayoutTextNameOffset>
|
||||||
|
<newLayoutOptionsTextOffset>20</newLayoutOptionsTextOffset>
|
||||||
|
|
||||||
|
</WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
</Defs>`;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System; // Required for Activator
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using Verse;
|
using Verse;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -46,7 +47,7 @@ namespace WulaFallenEmpire
|
|||||||
EventDef uiDef = DefDatabase<EventDef>.GetNamed(Props.uiDefName, false);
|
EventDef uiDef = DefDatabase<EventDef>.GetNamed(Props.uiDefName, false);
|
||||||
if (uiDef != null)
|
if (uiDef != null)
|
||||||
{
|
{
|
||||||
Find.WindowStack.Add(new Dialog_CustomDisplay(uiDef));
|
Find.WindowStack.Add((Window)Activator.CreateInstance(uiDef.windowType, uiDef));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System; // Required for Activator
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using LudeonTK;
|
using LudeonTK;
|
||||||
using Verse;
|
using Verse;
|
||||||
@@ -45,7 +46,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Find.WindowStack.Add(new Dialog_CustomDisplay(currentDef));
|
Find.WindowStack.Add((Window)Activator.CreateInstance(currentDef.windowType, currentDef));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
// This logic is simplified from Effect_OpenCustomUI.OpenUI
|
// This logic is simplified from Effect_OpenCustomUI.OpenUI
|
||||||
// It assumes delayed actions always open a new dialog.
|
// It assumes delayed actions always open a new dialog.
|
||||||
Find.WindowStack.Add(new Dialog_CustomDisplay(nextDef));
|
Find.WindowStack.Add((Window)Activator.CreateInstance(nextDef.windowType, nextDef));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,277 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class Dialog_NewLayoutDisplay : 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<EventUIConfigDef>.GetNamed("Wula_EventUIConfig");
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Vector2 InitialSize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (def.windowSize != Vector2.zero)
|
||||||
|
{
|
||||||
|
return def.windowSize;
|
||||||
|
}
|
||||||
|
return Config.defaultWindowSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dialog_NewLayoutDisplay(EventDef def)
|
||||||
|
{
|
||||||
|
this.def = def;
|
||||||
|
this.forcePause = true;
|
||||||
|
this.absorbInputAroundWindow = true;
|
||||||
|
this.doCloseX = true;
|
||||||
|
|
||||||
|
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||||
|
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<int>(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 (!def.portraitPath.NullOrEmpty())
|
||||||
|
{
|
||||||
|
portrait = ContentFinder<Texture2D>.Get(def.portraitPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string bgPath = !def.backgroundImagePath.NullOrEmpty() ? def.backgroundImagePath : Config.defaultBackgroundImagePath;
|
||||||
|
if (!bgPath.NullOrEmpty())
|
||||||
|
{
|
||||||
|
background = ContentFinder<Texture2D>.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.ScaleToFit);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.showLabel)
|
||||||
|
{
|
||||||
|
Text.Font = Config.labelFont;
|
||||||
|
Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label);
|
||||||
|
Text.Font = GameFont.Small;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 假设一个统一的边距
|
||||||
|
float padding = Config.newLayoutPadding;
|
||||||
|
|
||||||
|
// 名称区域
|
||||||
|
float nameHeight = Config.newLayoutNameSize.y;
|
||||||
|
float nameWidth = Config.newLayoutNameSize.x;
|
||||||
|
Rect nameRect = new Rect(inRect.x + (inRect.width - nameWidth) / 2f, inRect.y + padding, nameWidth, nameHeight);
|
||||||
|
if (Config.drawBorders)
|
||||||
|
{
|
||||||
|
Widgets.DrawBox(nameRect);
|
||||||
|
}
|
||||||
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
|
Text.Font = GameFont.Medium;
|
||||||
|
Widgets.Label(nameRect, def.characterName);
|
||||||
|
Text.Font = GameFont.Small;
|
||||||
|
Text.Anchor = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
|
// 立绘区域
|
||||||
|
float lihuiWidth = Config.newLayoutLihuiSize.x;
|
||||||
|
float lihuiHeight = Config.newLayoutLihuiSize.y;
|
||||||
|
Rect lihuiRect = new Rect(inRect.x + (inRect.width - lihuiWidth) / 2f, nameRect.yMax + padding, lihuiWidth, lihuiHeight);
|
||||||
|
if (portrait != null)
|
||||||
|
{
|
||||||
|
GUI.DrawTexture(lihuiRect, portrait, ScaleMode.ScaleToFit);
|
||||||
|
}
|
||||||
|
if (Config.drawBorders)
|
||||||
|
{
|
||||||
|
Widgets.DrawBox(lihuiRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选项区域 (预先计算高度)
|
||||||
|
float optionButtonHeight = 30f; // 每个按钮的高度
|
||||||
|
float optionSpacing = 5f; // 按钮之间的间距
|
||||||
|
float calculatedOptionHeight = 0f;
|
||||||
|
if (def.options != null && def.options.Any())
|
||||||
|
{
|
||||||
|
calculatedOptionHeight = def.options.Count * optionButtonHeight + (def.options.Count - 1) * optionSpacing;
|
||||||
|
}
|
||||||
|
calculatedOptionHeight = Mathf.Max(calculatedOptionHeight, 100f); // 最小高度
|
||||||
|
|
||||||
|
float optionsWidth = Config.newLayoutOptionsWidth;
|
||||||
|
Rect optionRect = new Rect(inRect.x + (inRect.width - optionsWidth) / 2f, inRect.yMax - padding - calculatedOptionHeight, optionsWidth, calculatedOptionHeight);
|
||||||
|
|
||||||
|
// 描述区域
|
||||||
|
float textWidth = Config.newLayoutTextSize.x;
|
||||||
|
Rect textRect = new Rect(inRect.x + (inRect.width - textWidth) / 2f, lihuiRect.yMax + padding, textWidth, optionRect.y - (lihuiRect.yMax + padding) - padding);
|
||||||
|
if (Config.drawBorders)
|
||||||
|
{
|
||||||
|
Widgets.DrawBox(textRect);
|
||||||
|
}
|
||||||
|
Rect textInnerRect = textRect.ContractedBy(padding);
|
||||||
|
Widgets.Label(textInnerRect, selectedDescription);
|
||||||
|
|
||||||
|
// 选项列表的绘制
|
||||||
|
Listing_Standard listing = new Listing_Standard();
|
||||||
|
listing.Begin(optionRect); // 使用完整的 optionRect
|
||||||
|
if (def.options != null)
|
||||||
|
{
|
||||||
|
foreach (var option in def.options)
|
||||||
|
{
|
||||||
|
string reason;
|
||||||
|
bool conditionsMet = AreConditionsMet(option.conditions, out reason);
|
||||||
|
|
||||||
|
if (conditionsMet)
|
||||||
|
{
|
||||||
|
if (listing.ButtonText(option.label))
|
||||||
|
{
|
||||||
|
HandleAction(option.optionEffects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (option.hideWhenDisabled)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Rect rect = listing.GetRect(30f);
|
||||||
|
Widgets.ButtonText(rect, option.label, false, true, false);
|
||||||
|
TooltipHandler.TipRegion(rect, GetDisabledReason(option, reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listing.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAction(List<ConditionalEffects> conditionalEffects)
|
||||||
|
{
|
||||||
|
if (conditionalEffects.NullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var ce in conditionalEffects)
|
||||||
|
{
|
||||||
|
if (AreConditionsMet(ce.conditions, out _))
|
||||||
|
{
|
||||||
|
ce.Execute(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AreConditionsMet(List<Condition> 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<EventVariableManager>();
|
||||||
|
// 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<object> to get any type
|
||||||
|
return eventVarManager.GetVariable<object>(varName)?.ToString() ?? "";
|
||||||
|
}
|
||||||
|
return match.Value; // Keep placeholder if variable not found
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System; // Required for Activator
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -9,7 +10,7 @@ namespace WulaFallenEmpire
|
|||||||
public abstract class Effect
|
public abstract class Effect
|
||||||
{
|
{
|
||||||
public float weight = 1.0f;
|
public float weight = 1.0f;
|
||||||
public abstract void Execute(Dialog_CustomDisplay dialog = null);
|
public abstract void Execute(Window dialog = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Effect_OpenCustomUI : Effect
|
public class Effect_OpenCustomUI : Effect
|
||||||
@@ -17,7 +18,7 @@ namespace WulaFallenEmpire
|
|||||||
public string defName;
|
public string defName;
|
||||||
public int delayTicks = 0;
|
public int delayTicks = 0;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (delayTicks > 0)
|
if (delayTicks > 0)
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Find.WindowStack.Add(new Dialog_CustomDisplay(nextDef));
|
Find.WindowStack.Add((Window)Activator.CreateInstance(nextDef.windowType, nextDef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -89,7 +90,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public class Effect_CloseDialog : Effect
|
public class Effect_CloseDialog : Effect
|
||||||
{
|
{
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
dialog?.Close();
|
dialog?.Close();
|
||||||
}
|
}
|
||||||
@@ -100,7 +101,7 @@ namespace WulaFallenEmpire
|
|||||||
public string message;
|
public string message;
|
||||||
public MessageTypeDef messageTypeDef;
|
public MessageTypeDef messageTypeDef;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (messageTypeDef == null)
|
if (messageTypeDef == null)
|
||||||
{
|
{
|
||||||
@@ -114,7 +115,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public IncidentDef incident;
|
public IncidentDef incident;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (incident == null)
|
if (incident == null)
|
||||||
{
|
{
|
||||||
@@ -140,7 +141,7 @@ namespace WulaFallenEmpire
|
|||||||
public FactionDef faction;
|
public FactionDef faction;
|
||||||
public int goodwillChange;
|
public int goodwillChange;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (faction == null)
|
if (faction == null)
|
||||||
{
|
{
|
||||||
@@ -166,7 +167,7 @@ namespace WulaFallenEmpire
|
|||||||
public string type; // Int, Float, String, Bool
|
public string type; // Int, Float, String, Bool
|
||||||
public bool forceSet = false;
|
public bool forceSet = false;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||||
if (!forceSet && eventVarManager.HasVariable(name))
|
if (!forceSet && eventVarManager.HasVariable(name))
|
||||||
@@ -199,7 +200,7 @@ namespace WulaFallenEmpire
|
|||||||
public FactionDef faction;
|
public FactionDef faction;
|
||||||
public string goodwillVariableName;
|
public string goodwillVariableName;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (faction == null)
|
if (faction == null)
|
||||||
{
|
{
|
||||||
@@ -225,7 +226,7 @@ namespace WulaFallenEmpire
|
|||||||
public int count = 1;
|
public int count = 1;
|
||||||
public string storeAs;
|
public string storeAs;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (kindDef == null)
|
if (kindDef == null)
|
||||||
{
|
{
|
||||||
@@ -264,7 +265,7 @@ namespace WulaFallenEmpire
|
|||||||
public ThingDef thingDef;
|
public ThingDef thingDef;
|
||||||
public int count = 1;
|
public int count = 1;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (thingDef == null)
|
if (thingDef == null)
|
||||||
{
|
{
|
||||||
@@ -298,7 +299,7 @@ namespace WulaFallenEmpire
|
|||||||
public string letterText;
|
public string letterText;
|
||||||
public LetterDef letterDef;
|
public LetterDef letterDef;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (kindDef == null)
|
if (kindDef == null)
|
||||||
{
|
{
|
||||||
@@ -356,7 +357,7 @@ namespace WulaFallenEmpire
|
|||||||
public string valueVariableName;
|
public string valueVariableName;
|
||||||
public VariableOperation operation;
|
public VariableOperation operation;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
@@ -434,7 +435,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public string name;
|
public string name;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
@@ -449,7 +450,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public QuestScriptDef quest;
|
public QuestScriptDef quest;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (quest == null)
|
if (quest == null)
|
||||||
{
|
{
|
||||||
@@ -468,7 +469,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public ResearchProjectDef research;
|
public ResearchProjectDef research;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (research == null)
|
if (research == null)
|
||||||
{
|
{
|
||||||
@@ -490,7 +491,7 @@ namespace WulaFallenEmpire
|
|||||||
public string letterLabel;
|
public string letterLabel;
|
||||||
public string letterText;
|
public string letterText;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
Map map = Find.CurrentMap;
|
Map map = Find.CurrentMap;
|
||||||
if (map == null)
|
if (map == null)
|
||||||
@@ -563,7 +564,7 @@ namespace WulaFallenEmpire
|
|||||||
public FactionDef factionDef;
|
public FactionDef factionDef;
|
||||||
public string variableName;
|
public string variableName;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (factionDef == null || string.IsNullOrEmpty(variableName))
|
if (factionDef == null || string.IsNullOrEmpty(variableName))
|
||||||
{
|
{
|
||||||
@@ -592,7 +593,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public string variableName;
|
public string variableName;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(variableName))
|
if (string.IsNullOrEmpty(variableName))
|
||||||
{
|
{
|
||||||
@@ -611,7 +612,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public string variableName;
|
public string variableName;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(variableName))
|
if (string.IsNullOrEmpty(variableName))
|
||||||
{
|
{
|
||||||
@@ -630,7 +631,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
public string variableName;
|
public string variableName;
|
||||||
|
|
||||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
public override void Execute(Window dialog = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(variableName))
|
if (string.IsNullOrEmpty(variableName))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System; // Add this line
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -26,6 +27,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public Vector2 windowSize = Vector2.zero;
|
public Vector2 windowSize = Vector2.zero;
|
||||||
|
|
||||||
|
public Type windowType = typeof(Dialog_CustomDisplay); // 默认窗口类型
|
||||||
public List<EventOption> options;
|
public List<EventOption> options;
|
||||||
public string backgroundImagePath;
|
public string backgroundImagePath;
|
||||||
public List<ConditionalEffects> immediateEffects;
|
public List<ConditionalEffects> immediateEffects;
|
||||||
@@ -83,7 +85,7 @@ namespace WulaFallenEmpire
|
|||||||
public List<Effect> randomlistEffects;
|
public List<Effect> randomlistEffects;
|
||||||
public List<LoopEffects> loopEffects;
|
public List<LoopEffects> loopEffects;
|
||||||
|
|
||||||
public void Execute(Dialog_CustomDisplay dialog)
|
public void Execute(Window dialog)
|
||||||
{
|
{
|
||||||
// Execute all standard effects
|
// Execute all standard effects
|
||||||
if (!effects.NullOrEmpty())
|
if (!effects.NullOrEmpty())
|
||||||
|
|||||||
@@ -22,5 +22,13 @@ namespace WulaFallenEmpire
|
|||||||
// Virtual Layout Offsets
|
// Virtual Layout Offsets
|
||||||
public float textNameOffset = 20f;
|
public float textNameOffset = 20f;
|
||||||
public float optionsTextOffset = 20f;
|
public float optionsTextOffset = 20f;
|
||||||
|
// New Layout Dimensions
|
||||||
|
public Vector2 newLayoutNameSize = new Vector2(200f, 50f);
|
||||||
|
public Vector2 newLayoutLihuiSize = new Vector2(300f, 400f);
|
||||||
|
public Vector2 newLayoutTextSize = new Vector2(600f, 200f);
|
||||||
|
public float newLayoutOptionsWidth = 600f;
|
||||||
|
public float newLayoutPadding = 20f;
|
||||||
|
public float newLayoutTextNameOffset = 20f;
|
||||||
|
public float newLayoutOptionsTextOffset = 20f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
<Compile Include="WULA_EventSystem\Dialog_ManageEventVariables.cs" />
|
<Compile Include="WULA_EventSystem\Dialog_ManageEventVariables.cs" />
|
||||||
<Compile Include="WULA_EventSystem\DelayedActionManager.cs" />
|
<Compile Include="WULA_EventSystem\DelayedActionManager.cs" />
|
||||||
<Compile Include="WULA_EventSystem\Dialog_CustomDisplay.cs" />
|
<Compile Include="WULA_EventSystem\Dialog_CustomDisplay.cs" />
|
||||||
|
<Compile Include="WULA_EventSystem\Dialog_NewLayoutDisplay.cs" />
|
||||||
<Compile Include="WULA_EventSystem\Effect.cs" />
|
<Compile Include="WULA_EventSystem\Effect.cs" />
|
||||||
<Compile Include="WULA_EventSystem\EventVariableManager.cs" />
|
<Compile Include="WULA_EventSystem\EventVariableManager.cs" />
|
||||||
<Compile Include="WULA_EventSystem\EventDef.cs" />
|
<Compile Include="WULA_EventSystem\EventDef.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user