feat: 新增虫群维护系统、营养网络塔及多种阿拉克涅建筑

This commit is contained in:
2025-12-25 13:57:06 +08:00
parent 1ed168a70c
commit 1473651a66
11 changed files with 233 additions and 97 deletions

Binary file not shown.

View File

@@ -675,15 +675,6 @@
<li>ARA_InsectCreep</li>
</relatedTerrain>
</building>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
</comps>
</ThingDef>
<ThingDef ParentName="BenchBase">
@@ -814,7 +805,7 @@
</researchPrerequisites>
<designationCategory>ARA_Buildings</designationCategory>
<comps>
<!-- 提供开关按钮 -->
<!-- 提供开关按钮 -->
<li Class="CompProperties_Flickable">
<commandTexture>UI/Commands/Vent</commandTexture>
<commandLabelKey>CommandDesignateOpenCloseVentLabel</commandLabelKey>
@@ -825,6 +816,13 @@
<!-- 这是设备的热交换功率。数值越大,制冷/制热速度越快。-->
<energyPerSecond>25</energyPerSecond>
</li>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
</comps>
</ThingDef>
@@ -1021,14 +1019,6 @@
<placeWorkers>
<li>PlaceWorker_GlowRadius</li>
</placeWorkers>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="CompProperties_Glower">
<glowRadius>7</glowRadius>
<glowColor>(220,210,171,0)</glowColor>
@@ -1236,13 +1226,6 @@
</building>
<!-- 不可建造,只能通过变形生成 -->
<comps Inherit="False">
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="ArachnaeSwarm.CompProperties_Morphable">
<!-- 休息速度增益例如1.0代表200%的速度 -->
<restGainMultiplier>1.0</restGainMultiplier>

View File

@@ -140,6 +140,13 @@
<tickerType>Normal</tickerType>
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
<fuelCapacity>10.0</fuelCapacity>
<fuelFilter>

View File

@@ -588,6 +588,13 @@
<li>ARA_Technology_4NPT</li>
</researchPrerequisites>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>20</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>5</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<!-- a. 我们新的队列物品生产组件 (带通量控制) -->
<li Class="ArachnaeSwarm.CompProperties_QueuedInteractiveProducerWithFlux">
<!-- 队列和交互设置 -->
@@ -706,6 +713,13 @@
</relatedTerrain>
</building>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>20</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>5</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<!-- a. 队列生产组件 -->
<li Class="ArachnaeSwarm.CompProperties_QueuedPawnSpawnerWithFlux">
<productionQueueLimit>5</productionQueueLimit>

View File

@@ -288,13 +288,6 @@
<tickerType>Normal</tickerType>
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="CompProperties_Forbiddable" />
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
<saveKeysPrefix>nutrition</saveKeysPrefix>
@@ -433,13 +426,6 @@
<tickerType>Normal</tickerType>
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="CompProperties_Forbiddable" />
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
<saveKeysPrefix>nutrition</saveKeysPrefix>
@@ -601,13 +587,6 @@
</statBases>
<tickerType>Normal</tickerType>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
<saveKeysPrefix>nutrition</saveKeysPrefix>
<fuelCapacity>50.0</fuelCapacity>

View File

@@ -60,13 +60,6 @@
<constructionSkillPrerequisite>4</constructionSkillPrerequisite>
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
</comps>
<modExtensions>
<li Class="ArachnaeSwarm.DefModExtension_DormancyVat">

View File

@@ -39,13 +39,6 @@
<ARA_Carapace>200</ARA_Carapace>
</costList>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>10</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
</li>
<li Class="CompProperties_Glower">
<overlightRadius>7.0</overlightRadius>
<glowRadius>14</glowRadius>

View File

@@ -103,4 +103,19 @@
<!-- 营养分配器/虫蜜 -->
<ARA_NutrientDispenser_MealsAvailable>可制作: {0} 份</ARA_NutrientDispenser_MealsAvailable>
<ARA_FuelLabel_Nutrition>虫蜜</ARA_FuelLabel_Nutrition>
<!-- 维护度 Gizmo -->
<ARA_SwarmMaintenance_Title>维护度</ARA_SwarmMaintenance_Title>
<ARA_SwarmMaintenance_DailyDecay_Short>消耗: {0}/天</ARA_SwarmMaintenance_DailyDecay_Short>
<ARA_SwarmMaintenance_TooltipTitle>【建筑维护度】</ARA_SwarmMaintenance_TooltipTitle>
<ARA_SwarmMaintenance_TooltipCurrent>当前: {0} / {1}</ARA_SwarmMaintenance_TooltipCurrent>
<ARA_SwarmMaintenance_TooltipDecay>每日消耗: {0}</ARA_SwarmMaintenance_TooltipDecay>
<ARA_SwarmMaintenance_TooltipCritical>⚠ 维护度严重不足!建筑正在受损</ARA_SwarmMaintenance_TooltipCritical>
<ARA_SwarmMaintenance_TooltipNeedsMaintenance>需要工艺种进行维护</ARA_SwarmMaintenance_TooltipNeedsMaintenance>
<ARA_SwarmMaintenance_TooltipGood>状态良好</ARA_SwarmMaintenance_TooltipGood>
<ARA_SwarmMaintenance_TooltipHint>工艺种会自动前来维护低于90%的建筑</ARA_SwarmMaintenance_TooltipHint>
<ARA_Gizmo_CallMaintainer>呼叫工艺种维护者</ARA_Gizmo_CallMaintainer>
<ARA_Msg_MaintainerCalled>已呼叫 {0} 前来维护建筑</ARA_Msg_MaintainerCalled>
<ARA_Msg_NoMaintainerAvailable>未找到空闲且可到达的工艺种维护者!</ARA_Msg_NoMaintainerAvailable>
</LanguageData>

View File

@@ -146,6 +146,7 @@
<Compile Include="Pawn_Comps\ARA_DratfableAnimals\CompProperties_DratfableAnimals.cs" />
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\CompProperties_SwarmMaintainer.cs" />
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\Comp_SwarmMaintainer.cs" />
<Compile Include="Building_Comps\ARA_SwarmMaintenance\Gizmo_SwarmMaintenance.cs" />
<Compile Include="Pawn_Comps\ARA_DratfableAnimals\BeastUnit.cs" />
<Compile Include="RoomRole\RoomRoleWorker_JellyVat.cs" />
<Compile Include="RoomRole\RoomRoleWorker_Incubator.cs" />

View File

@@ -90,25 +90,7 @@ namespace ArachnaeSwarm
return;
// 计算基础递减量每天递减量转换为每2500tick约0.0417天)的递减量
float baseDecayAmount = Props.maintenanceDecayPerDay * (2500f / 60000f);
// 检查是否为卵囊建筑,并根据孵化状态调整消耗
float decayMultiplier = 1f;
if (parent is Building_Ootheca ootheca)
{
if (!ootheca.IsIncubating)
{
// 未孵化时维护消耗减少80%
decayMultiplier = 0.2f;
}
else
{
// 孵化时根据活性调整(活性越高消耗越多)
decayMultiplier = 0.5f + ootheca.FluxEfficiency * 0.5f;
}
}
float decayAmount = baseDecayAmount * decayMultiplier;
float decayAmount = Props.maintenanceDecayPerDay * (2500f / 60000f);
currentMaintenance -= decayAmount;
// 确保不低于0
@@ -185,6 +167,41 @@ namespace ArachnaeSwarm
lastWarningState = false;
}
// 手动呼叫最近的维护者
public void CallMaintainer()
{
if (parent.Map == null) return;
Pawn bestPawn = null;
float minDist = float.MaxValue;
foreach (Pawn pawn in parent.Map.mapPawns.FreeColonistsSpawned)
{
var maintainerComp = pawn.TryGetComp<Comp_SwarmMaintainer>();
if (maintainerComp != null && !pawn.Downed && !pawn.Dead &&
pawn.CanReserveAndReach(parent, PathEndMode.Touch, Danger.Some))
{
float dist = pawn.Position.DistanceToSquared(parent.Position);
if (dist < minDist)
{
minDist = dist;
bestPawn = pawn;
}
}
}
if (bestPawn != null)
{
Job job = JobMaker.MakeJob(ARA_JobDefOf.ARA_SwarmMaintain, parent);
bestPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
Messages.Message("ARA_Msg_MaintainerCalled".Translate(bestPawn.LabelShort), parent, MessageTypeDefOf.PositiveEvent);
}
else
{
Messages.Message("ARA_Msg_NoMaintainerAvailable".Translate(), MessageTypeDefOf.RejectInput);
}
}
// 获取可维护的优先级用于WorkGiver排序
public float GetMaintenancePriority()
{
@@ -220,33 +237,21 @@ namespace ArachnaeSwarm
return text;
}
// 获取实际每日消耗(考虑孵化活性)
// 获取实际每日消耗
private float GetActualDecayPerDay()
{
float baseDecay = Props.maintenanceDecayPerDay;
float multiplier = 1f;
if (parent is Building_Ootheca ootheca)
{
if (!ootheca.IsIncubating)
{
multiplier = 0.2f;
}
else
{
multiplier = 0.5f + ootheca.FluxEfficiency * 0.5f;
}
}
return baseDecay * multiplier;
return Props.maintenanceDecayPerDay;
}
// 获取Gizmos命令按钮- 只保留调试功能
// 获取Gizmos命令按钮
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
// 只在玩家控制下显示
if (parent.Faction?.IsPlayer == true)
{
// 维护度计量条
yield return new Gizmo_SwarmMaintenance(this);
// 调试按钮 - 仅在GodMode下显示
if (DebugSettings.godMode)
{

View File

@@ -0,0 +1,146 @@
// File: Gizmo_SwarmMaintenance.cs
// 虫群建筑维护度计量条 Gizmo
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
[StaticConstructorOnStartup]
public class Gizmo_SwarmMaintenance : Gizmo
{
private readonly Comp_SwarmMaintenance comp;
private readonly Thing parentThing;
// 尺寸常量
private const float Width = 140f;
private const float GizmoHeight = 75f;
private const float Padding = 6f;
private const float BarHeight = 18f;
// 材质颜色
private static readonly Texture2D FullBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.3f, 0.9f));
private static readonly Texture2D MediumBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.7f, 0.2f, 0.9f));
private static readonly Texture2D LowBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.3f, 0.2f, 0.9f));
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.15f, 0.15f, 0.15f, 0.8f));
public Gizmo_SwarmMaintenance(Comp_SwarmMaintenance comp)
{
this.comp = comp;
this.parentThing = comp.parent;
Order = -120f; // 在活性和进度条之后,交互按钮之前
}
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, GetWidth(maxWidth), GizmoHeight);
Widgets.DrawWindowBackground(rect);
Rect innerRect = rect.ContractedBy(Padding);
float curY = innerRect.y;
// === 第一行:标题 + 按钮 ===
Text.Font = GameFont.Small;
Text.Anchor = TextAnchor.MiddleLeft;
GUI.color = Color.white;
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width - 26f, 18f);
Widgets.Label(titleRect, "ARA_SwarmMaintenance_Title".Translate());
// 右上角呼叫按钮
Rect btnRect = new Rect(innerRect.xMax - 20f, curY - 1f, 20f, 20f);
if (Widgets.ButtonImage(btnRect, ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false)))
{
comp.CallMaintainer();
}
TooltipHandler.TipRegion(btnRect, "ARA_Gizmo_CallMaintainer".Translate());
curY += 20f;
// === 第二行:消耗信息 ===
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleLeft;
GUI.color = new Color(0.7f, 0.7f, 0.7f);
Rect decayRect = new Rect(innerRect.x, curY, innerRect.width, 14f);
string decayText = "ARA_SwarmMaintenance_DailyDecay_Short".Translate(comp.Props.maintenanceDecayPerDay.ToString("F1"));
Widgets.Label(decayRect, decayText);
curY += 15f;
// === 第三行:进度条 ===
float percentage = comp.MaintenancePercentage;
Rect barRect = new Rect(innerRect.x, curY, innerRect.width, BarHeight);
// 背景
GUI.color = Color.white;
GUI.DrawTexture(barRect, EmptyBarTex);
// 根据百分比选择颜色
Texture2D barTex;
if (percentage > 0.6f)
barTex = FullBarTex;
else if (percentage > 0.3f)
barTex = MediumBarTex;
else
barTex = LowBarTex;
// 填充条
Rect fillRect = new Rect(barRect.x, barRect.y, barRect.width * percentage, barRect.height);
GUI.DrawTexture(fillRect, barTex);
// 百分比文字
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
Widgets.Label(barRect, percentage.ToStringPercent());
// === 工具提示 ===
Rect tooltipRect = new Rect(rect.x, rect.y, rect.width, rect.height);
tooltipRect.xMax -= 24f; // 排除按钮区域
if (Mouse.IsOver(tooltipRect))
{
Widgets.DrawHighlight(rect);
TooltipHandler.TipRegion(tooltipRect, GetTooltip());
}
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Small;
return new GizmoResult(GizmoState.Clear);
}
private string GetTooltip()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("ARA_SwarmMaintenance_TooltipTitle".Translate());
sb.AppendLine();
sb.AppendLine("ARA_SwarmMaintenance_TooltipCurrent".Translate(
comp.CurrentMaintenance.ToString("F1"),
comp.MaxMaintenance.ToString("F1")));
sb.AppendLine("ARA_SwarmMaintenance_TooltipDecay".Translate(comp.Props.maintenanceDecayPerDay.ToString("F1")));
sb.AppendLine();
if (comp.IsCritical)
{
sb.AppendLine("<color=orange>" + "ARA_SwarmMaintenance_TooltipCritical".Translate() + "</color>");
}
else if (comp.NeedsMaintenance)
{
sb.AppendLine("<color=yellow>" + "ARA_SwarmMaintenance_TooltipNeedsMaintenance".Translate() + "</color>");
}
else
{
sb.AppendLine("<color=green>" + "ARA_SwarmMaintenance_TooltipGood".Translate() + "</color>");
}
sb.AppendLine();
sb.AppendLine("ARA_SwarmMaintenance_TooltipHint".Translate());
return sb.ToString().TrimEndNewlines();
}
}
}