This commit is contained in:
2025-10-14 17:43:23 +08:00
7 changed files with 94 additions and 58 deletions

Binary file not shown.

View File

@@ -5,7 +5,7 @@
<organicAddedBodypart>true</organicAddedBodypart>
</HediffDef>
<HediffDef ParentName="AddedMutationBase">
<HediffDef ParentName="ARA_AddedMutationBase">
<defName>ArachnaeFighter_Swarm_Claws_Part</defName>
<label>战士种虫镰</label>
<labelNoun>战士种虫镰</labelNoun>
@@ -51,7 +51,7 @@
</comps>
</HediffDef>
<HediffDef ParentName="AddedMutationBase">
<HediffDef ParentName="ARA_AddedMutationBase">
<defName>ArachnaeNode_Race_Myrmecocystus_Tail_Part</defName>
<label>蜜罐种虫尾</label>
<labelNoun>蜜罐种虫尾</labelNoun>
@@ -146,7 +146,7 @@
</comps>
</HediffDef>
<HediffDef ParentName="AddedMutationBase">
<HediffDef ParentName="ARA_AddedMutationBase">
<defName>ArachnaeNode_Race_Skyraider_Wings_Part</defName>
<label>空天种翼翅</label>
<labelNoun>空天种翼翅</labelNoun>

View File

@@ -195,7 +195,7 @@
<hediffClass>Hediff_High</hediffClass>
<defaultLabelColor>(0.6, 0.8, 0.9)</defaultLabelColor>
<minSeverity>0.01</minSeverity>
<initialSeverity>0</initialSeverity>
<initialSeverity>0.01</initialSeverity>
<label>寿命记录</label>
<description>阿拉克涅虫族记录寿命的hediff正常情况下你不应该看见这个。</description>
<stages>

View File

@@ -1333,7 +1333,7 @@
<AccuracyLong>0.3</AccuracyLong>
<RangedWeapon_Cooldown>0.5</RangedWeapon_Cooldown>
<ARA_IncubationCost>450</ARA_IncubationCost>
<ARA_IncubationTime>15</ARA_IncubationTime>
<ARA_IncubationTime>0.5</ARA_IncubationTime>
</statBases>
<verbs>
<li>

View File

@@ -7,7 +7,8 @@
<SafeTemperatureRange>安全范围</SafeTemperatureRange>
<CannotStartProduction>无法开始生产</CannotStartProduction>
<NoFuel>无燃料</NoFuel>
<StartProduction>开始生产 {0}{1} 营养)</StartProduction>
<StartProduction>开始生产 {0}</StartProduction>
<ARA_ProductionCost>({0} 营养)</ARA_ProductionCost>
<CommandCancelProduction>取消生产</CommandCancelProduction>
<CommandCancelProductionDesc>停止当前的生产流程。</CommandCancelProductionDesc>
<Producing>正在生产 {0}</Producing>
@@ -23,4 +24,6 @@
<ARA_Incubate>孵化 {0}</ARA_Incubate>
<ARA_CocoonCooldown>茧正在稳定中:{0}</ARA_CocoonCooldown>
<ARA_ProducingListTitle>正在生产:</ARA_ProducingListTitle>
</LanguageData>

View File

@@ -307,17 +307,16 @@ namespace ArachnaeSwarm
// 获取营养需求 - 直接从 ProcessDef 中读取
float nutritionCost = process.totalNutritionNeeded;
string label = "StartProduction".Translate(process.thingDef.label) + " " + "ARA_ProductionCost".Translate(nutritionCost.ToString("F0"));
if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
{
// 修改:在未研究完成的情况下也显示营养需求
string disabledText = "StartProduction".Translate(process.thingDef.label, nutritionCost.ToString("F1")) +
" (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")";
string disabledText = label + " (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")";
yield return new FloatMenuOption(disabledText, null);
}
else
{
// 修改:使用新的翻译键显示营养需求
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label, nutritionCost.ToString("F1")), () =>
yield return new FloatMenuOption(label, () =>
{
this._selectedProcess = process;
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_StartInteractiveProduction"), parent);

View File

@@ -108,13 +108,15 @@ namespace ArachnaeSwarm
foreach (var process in Processes)
{
string label = "StartProduction".Translate(process.thingDef.label) + " " + "ARA_ProductionCost".Translate(process.totalNutritionNeeded.ToString("F0"));
if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
{
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label) + " (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")", null);
yield return new FloatMenuOption(label + " (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")", null);
}
else
{
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
yield return new FloatMenuOption(label, () =>
{
this.selectedProcess = process;
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_AddProcessToQueueJob"), parent);
@@ -134,33 +136,32 @@ namespace ArachnaeSwarm
public override void CompTick()
{
base.CompTick();
var producingOrders = productionOrders.Where(o => o.productionUntilTick > 0).ToList();
bool hasFuel = FuelComp?.HasFuel ?? true;
float ambientTemperature = parent.AmbientTemperature;
bool isTempSafe = ambientTemperature >= Props.minSafeTemperature && ambientTemperature <= Props.maxSafeTemperature;
foreach(var order in producingOrders)
if (hasFuel)
{
// 关键修复:检查时间戳有效性
if (order.productionUntilTick <= 0)
{
Log.Error($"Invalid productionUntilTick: {order.productionUntilTick} for {order.process?.thingDef?.defName}. Skipping.");
continue;
}
float ambientTemperature = parent.AmbientTemperature;
bool isTempSafe = ambientTemperature >= Props.minSafeTemperature && ambientTemperature <= Props.maxSafeTemperature;
if(hasFuel && isTempSafe)
foreach(var order in producingOrders)
{
order.ticksUnderOptimalConditions++;
order.productionUntilTick--; // 倒计时
if (isTempSafe)
{
order.ticksUnderOptimalConditions++;
}
else
{
float tempDelta = (ambientTemperature > Props.maxSafeTemperature) ? ambientTemperature - Props.maxSafeTemperature : Props.minSafeTemperature - ambientTemperature;
order.temperaturePenaltyPercent = Mathf.Min(1f, order.temperaturePenaltyPercent + tempDelta * Props.penaltyPerDegreePerTick);
}
}
if (!isTempSafe)
{
float tempDelta = (ambientTemperature > Props.maxSafeTemperature) ? ambientTemperature - Props.maxSafeTemperature : Props.minSafeTemperature - ambientTemperature;
order.temperaturePenaltyPercent = Mathf.Min(1f, order.temperaturePenaltyPercent + tempDelta * Props.penaltyPerDegreePerTick);
}
// 修复:移除原来的 order.productionUntilTick++ 逻辑
// 没有燃料时暂停生产
}
// 如果没有燃料则上面的代码块不执行productionUntilTick自然就暂停了
if (FuelComp != null)
{
float totalConsumptionRatePerDay = 0f;
@@ -168,7 +169,7 @@ namespace ArachnaeSwarm
{
foreach (var order in producingOrders)
{
if (order.process.totalNutritionNeeded > 0 && order.process.productionTicks > 0)
if (order.process != null && order.process.totalNutritionNeeded > 0 && order.process.productionTicks > 0)
{
totalConsumptionRatePerDay += (order.process.totalNutritionNeeded / order.process.productionTicks) * 60000f;
}
@@ -179,10 +180,10 @@ namespace ArachnaeSwarm
productionOrders.RemoveAll(order =>
{
if (order.productionUntilTick > 0 && Find.TickManager.TicksGame >= order.productionUntilTick)
if (order.productionUntilTick == 0)
{
FinishProduction(order);
return true;
return true;
}
return false;
});
@@ -195,14 +196,14 @@ namespace ArachnaeSwarm
{
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
int modifiedDelay = (int)(waitingOrder.process.productionTicks / speedFactor);
waitingOrder.productionUntilTick = Find.TickManager.TicksGame + modifiedDelay;
waitingOrder.productionUntilTick = modifiedDelay;
}
}
}
private (QualityCategory quality, float baseScore, float penalty) GetEstimatedQualityDetails(QueuedProcessOrder order)
{
if (order == null || Props.qualityThresholds.NullOrEmpty())
if (order == null || order.process == null || Props.qualityThresholds.NullOrEmpty())
{
return (QualityCategory.Normal, 0f, 0f);
}
@@ -217,6 +218,10 @@ namespace ArachnaeSwarm
break;
}
}
if (finalQuality == QualityCategory.Awful && Props.qualityThresholds.Any())
{
finalQuality = Props.qualityThresholds.OrderBy(q => q.threshold).First().quality;
}
return (finalQuality, progress, order.temperaturePenaltyPercent);
}
@@ -253,25 +258,37 @@ namespace ArachnaeSwarm
int producingCount = productionOrders.Count(o => o.productionUntilTick > 0);
int queuedCount = productionOrders.Count - producingCount;
sb.AppendLine($"生产槽位: {producingCount} / {Props.productionQueueLimit}");
if (queuedCount > 0) sb.AppendLine($"等待队列: {queuedCount}");
sb.AppendLine("ProductionSlots".Translate(producingCount, Props.productionQueueLimit));
if (queuedCount > 0) sb.AppendLine("ProductionQueue".Translate(queuedCount));
if (FacilitiesComp != null)
{
float speedFactor = 1f + FacilitiesComp.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor"));
if (speedFactor != 1f) sb.AppendLine($"生产速度: {speedFactor.ToStringPercent()}");
if (speedFactor != 1f) sb.AppendLine("ProductionSpeed".Translate() + $": {speedFactor.ToStringPercent()}");
}
var producingNow = productionOrders.Where(o => o.productionUntilTick > 0).OrderBy(o => o.productionUntilTick);
var producingNow = productionOrders.Where(o => o.productionUntilTick > 0).OrderBy(o => o.productionUntilTick).ToList();
if (producingNow.Any())
{
sb.AppendLine("正在生产:");
foreach (var order in producingNow)
sb.AppendLine("ARA_ProducingListTitle".Translate());
for (int i = 0; i < producingNow.Count; i++)
{
var order = producingNow[i];
if (order.process == null) continue;
int remainingTicks = order.productionUntilTick - Find.TickManager.TicksGame;
sb.AppendLine($" {i + 1}. {order.process.thingDef.LabelCap}:");
float progress = 1f - (float)order.productionUntilTick / (float)order.process.productionTicks;
int remainingTicks = order.productionUntilTick;
sb.AppendLine(" " + "Progress".Translate() + ": " + GetProgressBar(progress) + " " + progress.ToStringPercent("F0"));
sb.AppendLine(" " + "TimeLeft".Translate() + ": " + remainingTicks.ToStringTicksToPeriod());
var qualityDetails = GetEstimatedQualityDetails(order);
sb.AppendLine($" - {order.process.thingDef.LabelCap}: {remainingTicks.ToStringTicksToPeriod(true, false, true, true)} (品质: {qualityDetails.quality.GetLabel()})");
sb.AppendLine(" " + "EstimatedQuality".Translate() + ": " + qualityDetails.quality.GetLabel());
sb.AppendLine(" " + "QualityProgress".Translate() + ": " +
GetQualityProgressBar(qualityDetails.baseScore, qualityDetails.penalty) + " " +
(qualityDetails.baseScore - qualityDetails.penalty).ToStringPercent("F0"));
}
}
else if (queuedCount == 0)
@@ -328,20 +345,11 @@ namespace ArachnaeSwarm
// 关键修复:检查加载后的时间戳有效性
if (order.productionUntilTick > 0)
{
// 如果生产结束时间已经过去,立即完成生产
if (Find.TickManager.TicksGame >= order.productionUntilTick)
// 倒计时模式下,不再需要复杂的加载后时间戳检查
// 只需要确保值不是负数即可
if (order.productionUntilTick < 0)
{
Log.Warning($"Production time already passed for {order.tempThingDefName}. Finishing immediately.");
FinishProduction(order);
return true;
}
// 如果时间戳异常(比如超过游戏当前时间太多),重新计算
else if (order.productionUntilTick - Find.TickManager.TicksGame > order.process.productionTicks * 10)
{
Log.Warning($"Abnormal production time detected for {order.tempThingDefName}. Recalculating.");
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
int modifiedDelay = (int)(order.process.productionTicks / speedFactor);
order.productionUntilTick = Find.TickManager.TicksGame + modifiedDelay;
order.productionUntilTick = -1; // 重置为等待状态
}
}
@@ -376,6 +384,32 @@ namespace ArachnaeSwarm
}
}
private string GetProgressBar(float progress, int barLength = 20)
{
int filledLength = Mathf.RoundToInt(progress * barLength);
StringBuilder bar = new StringBuilder();
bar.Append("[");
bar.Append(new string('█', filledLength));
bar.Append(new string('-', barLength - filledLength));
bar.Append("]");
return bar.ToString();
}
private string GetQualityProgressBar(float baseScore, float penalty, int barLength = 20)
{
int baseLength = Mathf.RoundToInt(baseScore * barLength);
int penaltyLength = Mathf.RoundToInt(penalty * barLength);
int actualLength = Mathf.Max(0, baseLength - penaltyLength);
StringBuilder bar = new StringBuilder();
bar.Append("[");
bar.Append(new string('█', actualLength));
bar.Append(new string('░', baseLength - actualLength));
bar.Append(new string('-', barLength - baseLength));
bar.Append("]");
return bar.ToString();
}
private void BuildProcessList()
{
_cachedProcesses = new List<ProcessDef>();