feat: 新增阿拉克涅虫卵囊及其孵化系统,包括营养液、维护机制和孵化质量奖励。
This commit is contained in:
Binary file not shown.
BIN
1.6/1.6/Assemblies/ArachnaeSwarm.pdb
Normal file
BIN
1.6/1.6/Assemblies/ArachnaeSwarm.pdb
Normal file
Binary file not shown.
@@ -145,10 +145,7 @@
|
||||
</li>
|
||||
</modExtensions>
|
||||
|
||||
<!-- ITab配置 -->
|
||||
<inspectorTabs>
|
||||
<li>ArachnaeSwarm.ITab_Ootheca_Incubation</li>
|
||||
</inspectorTabs>
|
||||
|
||||
|
||||
<costList>
|
||||
<ARA_InsectJelly>25</ARA_InsectJelly>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<OutputPath>..\..\1.6\1.6\Assemblies\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@@ -123,7 +123,7 @@
|
||||
<Compile Include="Buildings\Building_Incubatable.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\Building_Ootheca.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\CompProperties_IncubatorData.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\ITab_Ootheca_Incubation.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\Gizmo_IncubationProgress.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\JobDriver_OperateIncubator.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\OothecaIncubatorExtension.cs" />
|
||||
<Compile Include="Buildings\Building_ResearchBlueprintReader\Building_ResearchBlueprintReader.cs" />
|
||||
|
||||
@@ -333,73 +333,65 @@ namespace ArachnaeSwarm
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// 显示额外信息(简化版本,只显示速率,不显示因子)
|
||||
public override string GetInspectString()
|
||||
// 显示额外信息(方案A:孵化信息在前,维护信息在后)
|
||||
public override string GetInspectString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// === 第一部分:孵化状态 ===
|
||||
if (isIncubating && incubatingPawnKind != null)
|
||||
{
|
||||
float progressPercent = AdjustedProgressPercent;
|
||||
float daysRemaining = GetRemainingDays();
|
||||
float hoursRemaining = GetRemainingHours();
|
||||
|
||||
builder.AppendLine("正在孵化: " + incubatingPawnKind.LabelCap);
|
||||
builder.AppendLine("进度: " + progressPercent.ToStringPercent());
|
||||
|
||||
// 显示剩余时间
|
||||
string timeText = "剩余时间: " + daysRemaining.ToString("F1") + " 天";
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
var baseString = base.GetInspectString();
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (!string.IsNullOrEmpty(baseString))
|
||||
{
|
||||
builder.Append(baseString);
|
||||
}
|
||||
|
||||
if (isIncubating && incubatingPawnKind != null)
|
||||
{
|
||||
float progressPercent = AdjustedProgressPercent;
|
||||
float daysRemaining = GetRemainingDays();
|
||||
float hoursRemaining = GetRemainingHours();
|
||||
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("ARA_OothecaIncubator.Incubating".Translate() + ": " + incubatingPawnKind.LabelCap);
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_OothecaIncubator.Progress".Translate() + ": " + progressPercent.ToStringPercent());
|
||||
builder.AppendLine();
|
||||
|
||||
// 显示剩余时间
|
||||
string timeText = "ARA_OothecaIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.Hours".Translate() + ")";
|
||||
}
|
||||
builder.Append(timeText);
|
||||
|
||||
// 显示速度和质量(简化版本)
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_OothecaIncubator.Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_OothecaIncubator.Quality".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
else if (assignedLarva != null)
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
if (larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = larvaOperateTicksRemaining / 60f;
|
||||
builder.Append("ARA_OothecaIncubator.LarvaOperating".Translate() + ": " + secondsRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.SRemaining".Translate());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("ARA_OothecaIncubator.LarvaOnWay".Translate());
|
||||
}
|
||||
}
|
||||
else if (!isIncubating)
|
||||
{
|
||||
var config = IncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("ARA_OothecaIncubator.Target".Translate() + ": " + config.pawnKind.LabelCap);
|
||||
|
||||
// 只显示当前乘数,不显示条件详情
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_OothecaIncubator.SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_OothecaIncubator.QualityMultiplier".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " 小时)";
|
||||
}
|
||||
builder.AppendLine(timeText);
|
||||
|
||||
// 显示速度和质量
|
||||
builder.Append("速度: " + SpeedMultiplier.ToStringPercent() + " | 质量: " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
else if (assignedLarva != null)
|
||||
{
|
||||
if (larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = larvaOperateTicksRemaining / 60f;
|
||||
builder.Append("幼虫激活中: " + secondsRemaining.ToString("F1") + " 秒");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("幼虫赶路中...");
|
||||
}
|
||||
}
|
||||
else if (!isIncubating)
|
||||
{
|
||||
var config = IncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
builder.AppendLine("孵化目标: " + config.pawnKind.LabelCap);
|
||||
builder.Append("速度: " + SpeedMultiplier.ToStringPercent() + " | 质量: " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
}
|
||||
|
||||
// === 第二部分:基类信息(包括维护度等) ===
|
||||
var baseString = base.GetInspectString();
|
||||
if (!string.IsNullOrEmpty(baseString))
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append(baseString);
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 获取剩余时间(ticks)
|
||||
public float GetRemainingTicks()
|
||||
{
|
||||
@@ -438,6 +430,9 @@ namespace ArachnaeSwarm
|
||||
// 只有玩家派系才显示Gizmo
|
||||
if (Faction == Faction.OfPlayer)
|
||||
{
|
||||
// 始终显示双进度条Gizmo(内部会自动处理非孵化状态的显示)
|
||||
yield return new Gizmo_IncubationProgress(this);
|
||||
|
||||
// 不在孵化中时才显示切换目标按钮
|
||||
if (!isIncubating && IncubatorData?.IncubationConfigs?.Count > 0)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
// File: Gizmo_IncubationProgress.cs
|
||||
// 类似原版 Refuelable 的双进度条 Gizmo,显示孵化进度和品质
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public class Gizmo_IncubationProgress : Gizmo
|
||||
{
|
||||
private readonly Building_Ootheca ootheca;
|
||||
|
||||
// 尺寸常量
|
||||
private const float Width = 180f;
|
||||
private const float BarHeight = 14f;
|
||||
private const float LabelHeight = 14f;
|
||||
private const float Spacing = 4f;
|
||||
private const float Padding = 8f;
|
||||
|
||||
// 进度条材质
|
||||
private static readonly Texture2D IncubationBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
|
||||
private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
|
||||
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
|
||||
|
||||
public Gizmo_IncubationProgress(Building_Ootheca ootheca)
|
||||
{
|
||||
this.ootheca = ootheca;
|
||||
Order = -100f; // 显示在左侧
|
||||
}
|
||||
|
||||
public override float GetWidth(float maxWidth)
|
||||
{
|
||||
return Mathf.Min(Width, maxWidth);
|
||||
}
|
||||
|
||||
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
|
||||
{
|
||||
// 主矩形区域(向上偏移以容纳更高的内容)
|
||||
Rect rect = new Rect(topLeft.x, topLeft.y - 55f, GetWidth(maxWidth), 130f);
|
||||
Widgets.DrawWindowBackground(rect);
|
||||
|
||||
// 内部区域
|
||||
Rect innerRect = rect.ContractedBy(Padding);
|
||||
float curY = innerRect.y;
|
||||
|
||||
// 状态判断
|
||||
bool isIncubating = ootheca.isIncubating;
|
||||
bool hasLarva = ootheca.assignedLarva != null;
|
||||
var config = ootheca.IncubatorData?.SelectedConfig;
|
||||
|
||||
// === 标题(可点击切换目标) ===
|
||||
Text.Font = GameFont.Small;
|
||||
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
|
||||
|
||||
string title;
|
||||
if (isIncubating && ootheca.incubatingPawnKind != null)
|
||||
title = ootheca.incubatingPawnKind.LabelCap;
|
||||
else if (config != null)
|
||||
title = config.pawnKind.LabelCap;
|
||||
else
|
||||
title = "选择孵化目标...";
|
||||
|
||||
// 标题按钮(只有非孵化状态可点击)
|
||||
bool canSwitch = !isIncubating && !hasLarva && ootheca.IncubatorData?.IncubationConfigs?.Count > 0;
|
||||
if (canSwitch)
|
||||
{
|
||||
// 绘制按钮背景
|
||||
if (Mouse.IsOver(titleRect))
|
||||
{
|
||||
Widgets.DrawHighlight(titleRect);
|
||||
}
|
||||
|
||||
if (Widgets.ButtonInvisible(titleRect))
|
||||
{
|
||||
ShowTargetSwitchMenu();
|
||||
}
|
||||
|
||||
// 带下划线的标题(表示可点击)
|
||||
GUI.color = new Color(0.7f, 0.9f, 1f);
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width - 10f) + " ▼");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width));
|
||||
}
|
||||
curY += Text.LineHeight + Spacing;
|
||||
|
||||
// === 内容绘制 ===
|
||||
if (isIncubating)
|
||||
{
|
||||
// 孵化进度标签
|
||||
DrawLabeledProgressBar(ref curY, innerRect.x, innerRect.width,
|
||||
"孵化进度:", ootheca.AdjustedProgressPercent, IncubationBarTex);
|
||||
|
||||
curY += Spacing;
|
||||
|
||||
// 品质进度标签
|
||||
DrawLabeledProgressBar(ref curY, innerRect.x, innerRect.width,
|
||||
"品质进度:", ootheca.QualityPercent, QualityBarTex);
|
||||
}
|
||||
else if (hasLarva)
|
||||
{
|
||||
Text.Font = GameFont.Tiny;
|
||||
GUI.color = new Color(0.9f, 0.9f, 0.5f);
|
||||
string statusText = ootheca.larvaOperateTicksRemaining > 0 ? "幼虫激活中..." : "幼虫赶路中...";
|
||||
Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 30f), statusText);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
Text.Font = GameFont.Tiny;
|
||||
GUI.color = new Color(0.7f, 0.7f, 0.7f);
|
||||
string statusText = (config != null && config.IsResearchComplete) ? "就绪 - 点击上方切换目标" : "需要研究";
|
||||
Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), statusText);
|
||||
curY += 20f;
|
||||
|
||||
string stats = $"速度:{ootheca.SpeedMultiplier.ToStringPercent()} 质量:{ootheca.QualityMultiplier.ToStringPercent()}";
|
||||
Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 16f), stats);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
// === 工具提示 ===
|
||||
if (Mouse.IsOver(rect) && !Mouse.IsOver(titleRect))
|
||||
{
|
||||
Widgets.DrawHighlight(rect);
|
||||
TooltipHandler.TipRegion(rect, GetTooltip());
|
||||
}
|
||||
|
||||
Text.Font = GameFont.Small;
|
||||
return new GizmoResult(GizmoState.Clear);
|
||||
}
|
||||
|
||||
private void ShowTargetSwitchMenu()
|
||||
{
|
||||
var configs = ootheca.IncubatorData?.IncubationConfigs;
|
||||
if (configs == null || configs.Count == 0) return;
|
||||
|
||||
List<FloatMenuOption> options = new List<FloatMenuOption>();
|
||||
|
||||
for (int i = 0; i < configs.Count; i++)
|
||||
{
|
||||
var cfg = configs[i];
|
||||
int index = i;
|
||||
|
||||
string label = cfg.pawnKind.LabelCap;
|
||||
if (cfg.requiredResearch != null && !cfg.requiredResearch.IsFinished)
|
||||
{
|
||||
label += $" (需要: {cfg.requiredResearch.LabelCap})";
|
||||
options.Add(new FloatMenuOption(label, null)); // 禁用
|
||||
}
|
||||
else
|
||||
{
|
||||
label += $" ({cfg.daysRequired}天)";
|
||||
options.Add(new FloatMenuOption(label, () =>
|
||||
{
|
||||
ootheca.IncubatorData.SwitchToConfig(index);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Find.WindowStack.Add(new FloatMenu(options));
|
||||
}
|
||||
|
||||
// 带标签的进度条
|
||||
private void DrawLabeledProgressBar(ref float curY, float x, float width, string label, float percent, Texture2D barTex)
|
||||
{
|
||||
// 标签
|
||||
Text.Font = GameFont.Tiny;
|
||||
GUI.color = new Color(0.8f, 0.8f, 0.8f);
|
||||
Widgets.Label(new Rect(x, curY, width, LabelHeight), label);
|
||||
GUI.color = Color.white;
|
||||
curY += LabelHeight;
|
||||
|
||||
// 进度条
|
||||
Rect barRect = new Rect(x, curY, width, BarHeight);
|
||||
Widgets.FillableBar(barRect, percent, barTex, EmptyBarTex, true);
|
||||
|
||||
// 百分比文字
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(barRect, percent.ToStringPercent("0"));
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
curY += BarHeight;
|
||||
}
|
||||
|
||||
private string GetTooltip()
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
// 孵化目标
|
||||
if (ootheca.incubatingPawnKind != null)
|
||||
{
|
||||
sb.AppendLine("正在孵化: " + ootheca.incubatingPawnKind.LabelCap);
|
||||
}
|
||||
|
||||
// 进度信息
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("孵化进度: " + ootheca.AdjustedProgressPercent.ToStringPercent());
|
||||
sb.AppendLine("品质进度: " + ootheca.QualityPercent.ToStringPercent());
|
||||
|
||||
// 剩余时间
|
||||
float daysRemaining = ootheca.GetRemainingDays();
|
||||
if (daysRemaining > 0 && daysRemaining < float.MaxValue)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("剩余时间: " + daysRemaining.ToString("F1") + " 天");
|
||||
}
|
||||
|
||||
// 速度和质量乘数
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("速度倍率: " + ootheca.SpeedMultiplier.ToStringPercent());
|
||||
sb.AppendLine("质量倍率: " + ootheca.QualityMultiplier.ToStringPercent());
|
||||
|
||||
// 详细因子
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(ootheca.GetSpeedFactorsDescription());
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(ootheca.GetQualityFactorsDescription());
|
||||
|
||||
return sb.ToString().TrimEndNewlines();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class ITab_Ootheca_Incubation : ITab
|
||||
{
|
||||
private const float BarHeight = 20f;
|
||||
private const float Margin = 10f;
|
||||
private const float LabelHeight = 30f;
|
||||
private const float SmallLabelHeight = 20f;
|
||||
private const float ButtonHeight = 25f;
|
||||
private const float TabWidth = 320f;
|
||||
private const float TabHeight = 420f; // 增加标签页高度以容纳更多间距
|
||||
|
||||
private Vector2 scrollPosition = Vector2.zero;
|
||||
private const float ViewHeight = 450f; // 增加滚动区域高度
|
||||
|
||||
public override bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
// 只显示给玩家派系
|
||||
return SelThing.Faction == Faction.OfPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public ITab_Ootheca_Incubation()
|
||||
{
|
||||
size = new Vector2(TabWidth, TabHeight);
|
||||
labelKey = "IncubationTab";
|
||||
tutorTag = "Incubation";
|
||||
}
|
||||
|
||||
protected override void FillTab()
|
||||
{
|
||||
|
||||
Rect rect = new Rect(0f, 0f, size.x, size.y).ContractedBy(Margin);
|
||||
Widgets.DrawMenuSection(rect);
|
||||
Building_Ootheca ootheca = SelThing as Building_Ootheca;
|
||||
if (ootheca == null)
|
||||
{
|
||||
Widgets.Label(rect, "NotAnOotheca".Translate());
|
||||
return;
|
||||
}
|
||||
rect = rect.ContractedBy(5f);
|
||||
|
||||
// 创建一个可滚动区域
|
||||
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, ViewHeight);
|
||||
Rect scrollRect = new Rect(rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
Widgets.BeginScrollView(scrollRect, ref scrollPosition, viewRect);
|
||||
|
||||
float curY = 0f;
|
||||
|
||||
// 显示标题
|
||||
Rect titleRect = new Rect(0f, curY, viewRect.width, LabelHeight);
|
||||
string title = "IncubationProgress".Translate();
|
||||
Text.Font = GameFont.Medium;
|
||||
Widgets.Label(titleRect, title);
|
||||
Text.Font = GameFont.Small;
|
||||
curY += LabelHeight + 15f;
|
||||
// 显示速度和质量乘数按钮
|
||||
float buttonWidth = (viewRect.width - 10f) / 2f;
|
||||
|
||||
// 速度按钮
|
||||
Rect speedButtonRect = new Rect(0f, curY, buttonWidth, ButtonHeight);
|
||||
string speedText = "Speed".Translate() + ": " + ootheca.SpeedMultiplier.ToStringPercent();
|
||||
|
||||
// 设置按钮颜色
|
||||
Color speedColor = Color.white;
|
||||
if (ootheca.SpeedMultiplier != 1.0f)
|
||||
{
|
||||
speedColor = ootheca.SpeedMultiplier > 1.0f ?
|
||||
new Color(0.2f, 0.8f, 0.2f) :
|
||||
new Color(0.8f, 0.8f, 0.2f);
|
||||
}
|
||||
|
||||
// 绘制速度按钮
|
||||
if (Widgets.ButtonText(speedButtonRect, speedText, true, true, speedColor))
|
||||
{
|
||||
// 按钮点击操作(可选)
|
||||
// 可以在这里显示详细信息的窗口
|
||||
}
|
||||
|
||||
// 为速度按钮添加工具提示
|
||||
TooltipHandler.TipRegion(speedButtonRect, () => ootheca.GetSpeedFactorsDescription(), 987654321);
|
||||
|
||||
// 质量按钮
|
||||
Rect qualityButtonRect = new Rect(buttonWidth + 10f, curY, buttonWidth, ButtonHeight);
|
||||
string qualityText = "Quality".Translate() + ": " + ootheca.QualityMultiplier.ToStringPercent();
|
||||
|
||||
// 设置按钮颜色
|
||||
Color qualityColor = Color.white;
|
||||
float qualityMultiplier = ootheca.QualityMultiplier;
|
||||
if (qualityMultiplier != 1.0f)
|
||||
{
|
||||
if (qualityMultiplier > 0.9f)
|
||||
qualityColor = new Color(0.2f, 0.8f, 0.2f);
|
||||
else if (qualityMultiplier > 0.7f)
|
||||
qualityColor = new Color(0.8f, 0.8f, 0.2f);
|
||||
else if (qualityMultiplier > 0.5f)
|
||||
qualityColor = new Color(0.9f, 0.6f, 0.2f);
|
||||
else
|
||||
qualityColor = new Color(0.8f, 0.2f, 0.2f);
|
||||
}
|
||||
|
||||
// 绘制质量按钮
|
||||
if (Widgets.ButtonText(qualityButtonRect, qualityText, true, true, qualityColor))
|
||||
{
|
||||
// 按钮点击操作(可选)
|
||||
// 可以在这里显示详细信息的窗口
|
||||
}
|
||||
|
||||
// 为质量按钮添加工具提示
|
||||
TooltipHandler.TipRegion(qualityButtonRect, () => ootheca.GetQualityFactorsDescription(), 987654322);
|
||||
|
||||
curY += ButtonHeight + 25f; // 增加按钮与目标显示之间的间距
|
||||
|
||||
// 如果在孵化中,显示进度条
|
||||
if (ootheca.isIncubating && ootheca.incubatingPawnKind != null)
|
||||
{
|
||||
// 使用调整后的进度百分比
|
||||
float progressPercent = ootheca.AdjustedProgressPercent;
|
||||
float qualityPercent = ootheca.QualityPercent;
|
||||
|
||||
// 获取调整后的剩余时间
|
||||
float daysRemaining = ootheca.GetRemainingDays();
|
||||
float hoursRemaining = ootheca.GetRemainingHours();
|
||||
|
||||
// 显示目标
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(targetRect, "Target".Translate() + ": " + ootheca.incubatingPawnKind.LabelCap);
|
||||
|
||||
curY += SmallLabelHeight + 20f;
|
||||
|
||||
// 显示孵化进度条
|
||||
Rect progressBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
|
||||
// 在进度条正上方居中添加标签
|
||||
Rect progressLabelRect = new Rect(progressBarRect.x, progressBarRect.y - 20, progressBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
Widgets.Label(progressLabelRect, "IncubationProgressLabel".Translate());
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
// 绘制进度条
|
||||
Widgets.FillableBar(progressBarRect, progressPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.2f, 0.5f)));
|
||||
Widgets.FillableBarChangeArrows(progressBarRect, progressPercent);
|
||||
|
||||
// 进度条文字(百分比)
|
||||
string progressText = $"{progressPercent:P0}";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(progressBarRect, progressText);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
curY += BarHeight + 30f; // 增加孵化条与质量条之间的间距
|
||||
|
||||
// 显示质量进度条
|
||||
Rect qualityBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
|
||||
// 在质量进度条正上方居中添加标签
|
||||
Rect qualityLabelRect = new Rect(qualityBarRect.x, qualityBarRect.y - 20, qualityBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
Widgets.Label(qualityLabelRect, "QualityProgress".Translate());
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
// 绘制质量进度条
|
||||
Widgets.FillableBar(qualityBarRect, qualityPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.4f, 0.8f, 0.5f)));
|
||||
|
||||
// 质量进度条文字(百分比)
|
||||
string qualityProgressText = $"{qualityPercent:P0}";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(qualityBarRect, qualityProgressText);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
// 在质量进度条上显示目标质量百分比
|
||||
Rect targetQualityRect = new Rect(qualityBarRect.x + qualityBarRect.width - 40, qualityBarRect.y, 40, BarHeight);
|
||||
GUI.color = new Color(0.8f, 0.8f, 0.8f, 0.7f);
|
||||
Text.Anchor = TextAnchor.MiddleRight;
|
||||
Widgets.Label(targetQualityRect, $"{ootheca.QualityMultiplier:P0}");
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
curY += BarHeight + 25f; // 增加质量条与剩余时间之间的间距
|
||||
|
||||
// 显示剩余时间
|
||||
Rect timeRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
string timeText = "ARA_OothecaIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "Hours".Translate() + ")";
|
||||
}
|
||||
Widgets.Label(timeRect, timeText);
|
||||
}
|
||||
else if (ootheca.assignedLarva != null)
|
||||
{
|
||||
// 如果有幼虫正在路上或操作中
|
||||
Rect statusRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 2);
|
||||
if (ootheca.larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = ootheca.larvaOperateTicksRemaining / 60f;
|
||||
Widgets.Label(statusRect, "LarvaIsActivatingOotheca".Translate() + "\n" +
|
||||
secondsRemaining.ToString("F1") + " " + "SecondsRemaining".Translate());
|
||||
}
|
||||
else
|
||||
{
|
||||
Widgets.Label(statusRect, "LarvaIsOnTheWay".Translate());
|
||||
}
|
||||
|
||||
// 为幼虫状态增加一些间距
|
||||
curY += SmallLabelHeight * 2 + 15f;
|
||||
|
||||
// 不在孵化中时,也显示目标配置
|
||||
var config = ootheca.IncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
curY += 10f;
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 3);
|
||||
string targetText = "ReadyToIncubate".Translate() + "\n" + config.pawnKind.LabelCap;
|
||||
|
||||
if (!config.IsResearchComplete && config.requiredResearch != null)
|
||||
{
|
||||
targetText += "\n" + "(" + "Requires".Translate() + ": " + config.requiredResearch.LabelCap + ")";
|
||||
}
|
||||
|
||||
Widgets.Label(targetRect, targetText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不在孵化中,显示当前选择的目标
|
||||
var config = ootheca.IncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 3);
|
||||
string targetText = "ReadyToIncubate".Translate() + "\n" + config.pawnKind.LabelCap;
|
||||
|
||||
if (!config.IsResearchComplete && config.requiredResearch != null)
|
||||
{
|
||||
targetText += "\n" + "(" + "Requires".Translate() + ": " + config.requiredResearch.LabelCap + ")";
|
||||
}
|
||||
|
||||
Widgets.Label(targetRect, targetText);
|
||||
|
||||
// 为静态显示增加一些底部间距
|
||||
curY += SmallLabelHeight * 3 + 10f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect noTargetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(noTargetRect, "NoIncubationTargetSelected".Translate());
|
||||
|
||||
curY += SmallLabelHeight + 10f;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加一些底部空白区域,让布局看起来不那么拥挤
|
||||
curY += 20f;
|
||||
|
||||
// 更新滚动区域的实际高度
|
||||
viewRect.height = curY;
|
||||
|
||||
Widgets.EndScrollView();
|
||||
}
|
||||
|
||||
// 检查是否在孵化间中(ITab内部使用)
|
||||
private bool IsInIncubatorRoom(Building_Ootheca ootheca)
|
||||
{
|
||||
var room = ootheca.GetRoom();
|
||||
if (room == null) return false;
|
||||
|
||||
return room.Role != null && room.Role.defName == "ARA_Incubator_Room";
|
||||
}
|
||||
|
||||
// 计算周围4格内的营养液数量(ITab内部使用)
|
||||
private int CountNearbyNutrientSolutions(Building_Ootheca ootheca)
|
||||
{
|
||||
var map = ootheca.Map;
|
||||
if (map == null) return 0;
|
||||
|
||||
int count = 0;
|
||||
int radius = 4; // 4格半径
|
||||
var position = ootheca.Position;
|
||||
|
||||
// 检查周围4格范围内的所有单元格
|
||||
for (int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
{
|
||||
IntVec3 cell = position + new IntVec3(x, 0, y);
|
||||
|
||||
// 检查单元格是否在地图内
|
||||
if (cell.InBounds(map))
|
||||
{
|
||||
// 检查地形是否为营养液
|
||||
TerrainDef terrain = map.terrainGrid.TerrainAt(cell);
|
||||
if (terrain != null && terrain.defName == "ARA_Incubator_Nutrient_Solution")
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// 计算房间质量因子(ITab内部使用)
|
||||
private float GetRoomQualityFactor(Building_Ootheca ootheca)
|
||||
{
|
||||
var room = ootheca.GetRoom();
|
||||
if (room == null) return 1.0f;
|
||||
|
||||
// 获取房间的ARA_IncubatorQualityFactor统计值
|
||||
var statDef = DefDatabase<RoomStatDef>.GetNamedSilentFail("ARA_IncubatorQualityFactor");
|
||||
if (statDef != null)
|
||||
{
|
||||
return room.GetStat(statDef);
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// 计算附近其他Ootheca的数量(ITab内部使用)
|
||||
private int CountNearbyOtherOothecas(Building_Ootheca ootheca)
|
||||
{
|
||||
var map = ootheca.Map;
|
||||
if (map == null) return 0;
|
||||
|
||||
int count = 0;
|
||||
var position = ootheca.Position;
|
||||
var room = ootheca.GetRoom();
|
||||
|
||||
// 查找地图上所有的Ootheca
|
||||
var allOothecas = map.listerThings.ThingsOfDef(ootheca.def);
|
||||
|
||||
foreach (var thing in allOothecas)
|
||||
{
|
||||
// 排除自己
|
||||
if (thing == ootheca) continue;
|
||||
|
||||
// 检查是否在同一个房间或附近(10格内)
|
||||
float distance = thing.Position.DistanceTo(position);
|
||||
var otherRoom = thing.GetRoom();
|
||||
|
||||
if ((room != null && room == otherRoom) || distance <= 10f)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
protected override void UpdateSize()
|
||||
{
|
||||
// 固定大小
|
||||
size = new Vector2(TabWidth, TabHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,64 +95,43 @@ namespace ArachnaeSwarm
|
||||
return bestCell;
|
||||
}
|
||||
|
||||
// 修改后的方法:寻找最近的播种或清理 Job
|
||||
// 修改后的方法:寻找最近的播种或清理 Job(原版逻辑:找最近可工作格子)
|
||||
private Job FindClosestSowableOrClearJob(Pawn pawn, WorkGiver_ArachnaeSow scanner)
|
||||
{
|
||||
IntVec3 bestClearCell = IntVec3.Invalid;
|
||||
Job bestClearJob = null;
|
||||
float bestClearDistSq = float.MaxValue;
|
||||
|
||||
IntVec3 bestSowCell = IntVec3.Invalid;
|
||||
Job bestSowJob = null;
|
||||
float bestSowDistSq = float.MaxValue;
|
||||
IntVec3 bestCell = IntVec3.Invalid;
|
||||
Job bestJob = null;
|
||||
float bestDistSq = float.MaxValue;
|
||||
|
||||
foreach (Zone zone in pawn.Map.zoneManager.AllZones)
|
||||
{
|
||||
if (zone is Zone_Growing growingZone)
|
||||
{
|
||||
// 检查种植区是否允许播种
|
||||
if (!growingZone.allowSow)
|
||||
continue;
|
||||
|
||||
ThingDef wantedPlant = growingZone.GetPlantDefToGrow();
|
||||
if (wantedPlant == null) continue;
|
||||
|
||||
foreach (IntVec3 cell in growingZone.Cells)
|
||||
{
|
||||
float distSq = pawn.Position.DistanceToSquared(cell);
|
||||
if (pawn.CanReach(cell, PathEndMode.ClosestTouch, Danger.Deadly))
|
||||
// 只考虑比当前最佳更近的格子
|
||||
if (distSq < bestDistSq && pawn.CanReach(cell, PathEndMode.ClosestTouch, Danger.Deadly))
|
||||
{
|
||||
Job potentialJob = scanner.JobOnCell(pawn, cell);
|
||||
if (potentialJob != null)
|
||||
{
|
||||
if (potentialJob.def == JobDefOf.CutPlant || potentialJob.def == JobDefOf.HaulToContainer || potentialJob.def == JobDefOf.HaulToCell)
|
||||
{
|
||||
if (distSq < bestClearDistSq)
|
||||
{
|
||||
bestClearDistSq = distSq;
|
||||
bestClearJob = potentialJob;
|
||||
}
|
||||
}
|
||||
else if (potentialJob.def == JobDefOf.Sow)
|
||||
{
|
||||
if (distSq < bestSowDistSq)
|
||||
{
|
||||
bestSowDistSq = distSq;
|
||||
bestSowJob = potentialJob;
|
||||
}
|
||||
}
|
||||
// 原版逻辑:找最近的可工作格子,不区分任务类型优先级
|
||||
bestDistSq = distSq;
|
||||
bestJob = potentialJob;
|
||||
bestCell = cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 优先返回清理 Job
|
||||
if (bestClearJob != null)
|
||||
{
|
||||
return bestClearJob;
|
||||
}
|
||||
// 其次返回播种 Job
|
||||
if (bestSowJob != null)
|
||||
{
|
||||
return bestSowJob;
|
||||
}
|
||||
return null;
|
||||
return bestJob;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,4 @@ namespace ArachnaeSwarm
|
||||
return canSow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace ArachnaeSwarm
|
||||
for (int i = 0; i < thingList.Count; i++)
|
||||
{
|
||||
Thing thing = thingList[i];
|
||||
if (thing.def == wantedPlantDef)
|
||||
if (thing.def == wantedPlantDefLocal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -122,6 +122,10 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!PlantUtility.PawnWillingToCutPlant_Job(plant, pawn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return JobMaker.MakeJob(JobDefOf.CutPlant, plant);
|
||||
}
|
||||
// 如果地块上的植物是我们想要种植的植物,并且它阻碍了相邻播种,则不割除
|
||||
@@ -155,6 +159,10 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!PlantUtility.PawnWillingToCutPlant_Job(plant2, pawn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (PlantUtility.TreeMarkedForExtraction(plant2))
|
||||
{
|
||||
return null;
|
||||
@@ -202,6 +210,10 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!PlantUtility.PawnWillingToCutPlant_Job(thing3, pawn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (PlantUtility.TreeMarkedForExtraction(thing3))
|
||||
{
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user