Merge branch 'master' of https://git.ra3battle.cn/Kalospacer/ArachnaeSwarm
This commit is contained in:
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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>();
|
||||
|
||||
Reference in New Issue
Block a user