Merge branch 'master' of https://git.ra3battle.cn/Kalospacer/ArachnaeSwarm
This commit is contained in:
Binary file not shown.
@@ -4,14 +4,21 @@
|
|||||||
<JobDef>
|
<JobDef>
|
||||||
<defName>ARA_StartInteractiveProduction</defName>
|
<defName>ARA_StartInteractiveProduction</defName>
|
||||||
<driverClass>ArachnaeSwarm.JobDriver_StartProduction</driverClass>
|
<driverClass>ArachnaeSwarm.JobDriver_StartProduction</driverClass>
|
||||||
<reportString>正在启动生产 TargetA.</reportString>
|
<reportString>正在启动孵化 TargetA.</reportString>
|
||||||
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||||
</JobDef>
|
</JobDef>
|
||||||
|
|
||||||
<JobDef>
|
<JobDef>
|
||||||
<defName>ARA_AddToQueueJob</defName>
|
<defName>ARA_AddToQueueJob</defName>
|
||||||
<driverClass>ArachnaeSwarm.JobDriver_AddToQueue</driverClass>
|
<driverClass>ArachnaeSwarm.JobDriver_AddToQueue</driverClass>
|
||||||
<reportString>正在添加生产订单。</reportString>
|
<reportString>正在添加虫族孵化订单。</reportString>
|
||||||
|
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||||
|
</JobDef>
|
||||||
|
|
||||||
|
<JobDef>
|
||||||
|
<defName>ARA_AddProcessToQueueJob</defName>
|
||||||
|
<driverClass>ArachnaeSwarm.JobDriver_AddProcessToQueue</driverClass>
|
||||||
|
<reportString>正在添加物品孵化订单。</reportString>
|
||||||
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||||
</JobDef>
|
</JobDef>
|
||||||
|
|
||||||
|
|||||||
@@ -309,6 +309,7 @@
|
|||||||
<thingDef>ARA_RW_Basic_Fist_Needle_Gun</thingDef>
|
<thingDef>ARA_RW_Basic_Fist_Needle_Gun</thingDef>
|
||||||
<productionTicks>40000</productionTicks>
|
<productionTicks>40000</productionTicks>
|
||||||
<totalNutritionNeeded>10</totalNutritionNeeded>
|
<totalNutritionNeeded>10</totalNutritionNeeded>
|
||||||
|
<!--<requiredResearch>ARA_Technology_5PAV</requiredResearch>-->
|
||||||
</li>
|
</li>
|
||||||
</processes>
|
</processes>
|
||||||
|
|
||||||
@@ -509,6 +510,7 @@
|
|||||||
<thingDef>ARA_RW_Basic_Acid_Bladder_Gun</thingDef>
|
<thingDef>ARA_RW_Basic_Acid_Bladder_Gun</thingDef>
|
||||||
<productionTicks>80000</productionTicks>
|
<productionTicks>80000</productionTicks>
|
||||||
<totalNutritionNeeded>30</totalNutritionNeeded>
|
<totalNutritionNeeded>30</totalNutritionNeeded>
|
||||||
|
<!--<requiredResearch>ARA_Technology_7VXI</requiredResearch>-->
|
||||||
</li>
|
</li>
|
||||||
</processes>
|
</processes>
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,130 @@
|
|||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
|
|
||||||
<!-- 2. 主建筑 "生物孵化池" -->
|
<!-- 3. 主建筑 "生物孵化池" -->
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>ARA_BioforgeIncubator_Thing</defName>
|
||||||
|
<label>生物质物品孵化池</label>
|
||||||
|
<description>一个大型的、需要消耗大量营养物质的孵化设施,可以同时孵化多个单位,并能通过链接外部设备来提高效率。</description>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/AncientHeatVent</texPath>
|
||||||
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<shaderType>CutoutComplex</shaderType>
|
||||||
|
<drawSize>(7,7)</drawSize>
|
||||||
|
</graphicData>
|
||||||
|
<size>(7,7)</size>
|
||||||
|
<tickerType>Normal</tickerType>
|
||||||
|
<stuffCategories Inherit="False"/>
|
||||||
|
<costStuffCount>0</costStuffCount>
|
||||||
|
<costList>
|
||||||
|
<ARA_Carapace>50</ARA_Carapace>
|
||||||
|
</costList>
|
||||||
|
<castEdgeShadows>false</castEdgeShadows>
|
||||||
|
<staticSunShadowHeight>0</staticSunShadowHeight>
|
||||||
|
<altitudeLayer>Building</altitudeLayer>
|
||||||
|
<passability>PassThroughOnly</passability>
|
||||||
|
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
|
||||||
|
<pathCost>50</pathCost>
|
||||||
|
<statBases>
|
||||||
|
<MaxHitPoints>250</MaxHitPoints>
|
||||||
|
<WorkToBuild>2800</WorkToBuild>
|
||||||
|
<Flammability>1.0</Flammability>
|
||||||
|
</statBases>
|
||||||
|
<placeWorkers>
|
||||||
|
<li>PlaceWorker_PreventInteractionSpotOverlap</li>
|
||||||
|
</placeWorkers>
|
||||||
|
<fillPercent>0.8</fillPercent>
|
||||||
|
<interactionCellOffset>(0,0,-1)</interactionCellOffset>
|
||||||
|
<hasInteractionCell>true</hasInteractionCell>
|
||||||
|
<designationCategory>ARA_Buildings</designationCategory>
|
||||||
|
<uiOrder>2600</uiOrder>
|
||||||
|
<surfaceType>Item</surfaceType>
|
||||||
|
<building>
|
||||||
|
<workTableRoomRole>Laboratory</workTableRoomRole>
|
||||||
|
<workTableNotInRoomRoleFactor>0.8</workTableNotInRoomRoleFactor>
|
||||||
|
</building>
|
||||||
|
<comps>
|
||||||
|
|
||||||
|
<!-- a. 我们新的队列物品生产组件 -->
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_QueuedInteractiveProducer">
|
||||||
|
<!-- 队列和交互设置 -->
|
||||||
|
<productionQueueLimit>3</productionQueueLimit>
|
||||||
|
<minNutritionToStart>1.0</minNutritionToStart>
|
||||||
|
<whitelist>
|
||||||
|
<li>ArachnaeNode_Race_WeaponSmith</li> <!-- 示例:允许普通殖民者操作 -->
|
||||||
|
</whitelist>
|
||||||
|
|
||||||
|
<!-- 质量系统设置 -->
|
||||||
|
<minSafeTemperature>10</minSafeTemperature>
|
||||||
|
<maxSafeTemperature>30</maxSafeTemperature>
|
||||||
|
<penaltyPerDegreePerTick>0.00001</penaltyPerDegreePerTick>
|
||||||
|
<qualityThresholds>
|
||||||
|
<li>
|
||||||
|
<quality>Legendary</quality>
|
||||||
|
<threshold>0.99</threshold>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<quality>Masterwork</quality>
|
||||||
|
<threshold>0.90</threshold>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<quality>Excellent</quality>
|
||||||
|
<threshold>0.70</threshold>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<quality>Good</quality>
|
||||||
|
<threshold>0.50</threshold>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<quality>Normal</quality>
|
||||||
|
<threshold>0.20</threshold>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<quality>Poor</quality>
|
||||||
|
<threshold>0.10</threshold>
|
||||||
|
</li>
|
||||||
|
</qualityThresholds>
|
||||||
|
|
||||||
|
<!-- 生产列表 -->
|
||||||
|
<processes>
|
||||||
|
<li>
|
||||||
|
<thingDef>ARA_RW_Basic_Acid_Bladder_Gun</thingDef>
|
||||||
|
<productionTicks>80000</productionTicks>
|
||||||
|
<totalNutritionNeeded>30</totalNutritionNeeded>
|
||||||
|
<requiredResearch>ARA_Technology_7VXI</requiredResearch>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<thingDef>ARA_RW_Basic_Fist_Needle_Gun</thingDef>
|
||||||
|
<productionTicks>40000</productionTicks>
|
||||||
|
<totalNutritionNeeded>10</totalNutritionNeeded>
|
||||||
|
<requiredResearch>ARA_Technology_5PAV</requiredResearch>
|
||||||
|
</li>
|
||||||
|
</processes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- b. 我们的营养燃料组件 -->
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
|
||||||
|
<fuelCapacity>100.0</fuelCapacity>
|
||||||
|
<fuelFilter>
|
||||||
|
<categories>
|
||||||
|
<li>Foods</li>
|
||||||
|
</categories>
|
||||||
|
</fuelFilter>
|
||||||
|
<fuelGizmoLabel>生物质</fuelGizmoLabel>
|
||||||
|
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||||
|
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- c. 原版的设施链接接收组件 -->
|
||||||
|
<li Class="CompProperties_AffectedByFacilities">
|
||||||
|
<linkableFacilities>
|
||||||
|
<li>ARA_IncubationAccelerator</li>
|
||||||
|
</linkableFacilities>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</comps>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
<ThingDef ParentName="BuildingBase">
|
<ThingDef ParentName="BuildingBase">
|
||||||
<defName>ARA_BioforgeIncubator</defName>
|
<defName>ARA_BioforgeIncubator</defName>
|
||||||
<label>生物质孵化池</label>
|
<label>生物质孵化池</label>
|
||||||
|
|||||||
@@ -111,6 +111,13 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (var process in Props.processes)
|
foreach (var process in Props.processes)
|
||||||
|
{
|
||||||
|
if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
|
||||||
|
{
|
||||||
|
string disabledText = "StartProduction".Translate(process.thingDef.label) + " (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")";
|
||||||
|
yield return new FloatMenuOption(disabledText, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
|
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
|
||||||
{
|
{
|
||||||
@@ -120,6 +127,7 @@ namespace ArachnaeSwarm
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void StartProduction()
|
public void StartProduction()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
// Data contract for a single production order in the queue
|
||||||
|
public class QueuedProcessOrder : IExposable
|
||||||
|
{
|
||||||
|
public ProcessDef process; // Using the existing ProcessDef
|
||||||
|
public int productionUntilTick = -1;
|
||||||
|
|
||||||
|
// Quality-related fields
|
||||||
|
public int ticksUnderOptimalConditions;
|
||||||
|
public float temperaturePenaltyPercent;
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_Deep.Look(ref process, "process");
|
||||||
|
Scribe_Values.Look(ref productionUntilTick, "productionUntilTick", -1);
|
||||||
|
Scribe_Values.Look(ref ticksUnderOptimalConditions, "ticksUnderOptimalConditions", 0);
|
||||||
|
Scribe_Values.Look(ref temperaturePenaltyPercent, "temperaturePenaltyPercent", 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties for the new queued producer component
|
||||||
|
public class CompProperties_QueuedInteractiveProducer : CompProperties
|
||||||
|
{
|
||||||
|
public List<ProcessDef> processes;
|
||||||
|
public List<PawnKindDef> whitelist;
|
||||||
|
public int productionQueueLimit = 1;
|
||||||
|
public float minNutritionToStart = 0.1f;
|
||||||
|
|
||||||
|
// Quality-related properties from CompInteractiveProducer
|
||||||
|
public float minSafeTemperature = 7f;
|
||||||
|
public float maxSafeTemperature = 32f;
|
||||||
|
public float penaltyPerDegreePerTick = 0.00001f;
|
||||||
|
public List<QualityThreshold> qualityThresholds;
|
||||||
|
public IntRange spawnCount = new IntRange(1, 1);
|
||||||
|
|
||||||
|
public CompProperties_QueuedInteractiveProducer()
|
||||||
|
{
|
||||||
|
compClass = typeof(CompQueuedInteractiveProducer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main component logic
|
||||||
|
public class CompQueuedInteractiveProducer : ThingComp
|
||||||
|
{
|
||||||
|
private List<QueuedProcessOrder> productionOrders = new List<QueuedProcessOrder>();
|
||||||
|
public ProcessDef selectedProcess; // For passing to the JobDriver
|
||||||
|
|
||||||
|
private CompRefuelableNutrition _fuelComp;
|
||||||
|
private CompAffectedByFacilities _facilitiesComp;
|
||||||
|
|
||||||
|
public CompProperties_QueuedInteractiveProducer Props => (CompProperties_QueuedInteractiveProducer)props;
|
||||||
|
private CompRefuelableNutrition FuelComp => _fuelComp ?? (_fuelComp = parent.GetComp<CompRefuelableNutrition>());
|
||||||
|
private CompAffectedByFacilities FacilitiesComp => _facilitiesComp ?? (_facilitiesComp = parent.GetComp<CompAffectedByFacilities>());
|
||||||
|
|
||||||
|
public override void Initialize(CompProperties props)
|
||||||
|
{
|
||||||
|
base.Initialize(props);
|
||||||
|
_fuelComp = parent.GetComp<CompRefuelableNutrition>();
|
||||||
|
_facilitiesComp = parent.GetComp<CompAffectedByFacilities>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
|
||||||
|
{
|
||||||
|
if (Props.whitelist == null || !Props.whitelist.Contains(selPawn.kindDef)) yield break;
|
||||||
|
if (FuelComp != null && (!FuelComp.HasFuel || FuelComp.NutritionStored < Props.minNutritionToStart))
|
||||||
|
{
|
||||||
|
yield return new FloatMenuOption("CannotStartProduction".Translate(), null);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var process in Props.processes)
|
||||||
|
{
|
||||||
|
if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
|
||||||
|
{
|
||||||
|
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label) + " (" + "Requires".Translate() + ": " + process.requiredResearch.label + ")", null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
|
||||||
|
{
|
||||||
|
this.selectedProcess = process;
|
||||||
|
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_AddProcessToQueueJob"), parent);
|
||||||
|
selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddToQueue()
|
||||||
|
{
|
||||||
|
if (selectedProcess == null) return;
|
||||||
|
productionOrders.Add(new QueuedProcessOrder { process = selectedProcess });
|
||||||
|
selectedProcess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Update progress and penalties for active orders
|
||||||
|
foreach(var order in producingOrders)
|
||||||
|
{
|
||||||
|
if(hasFuel && isTempSafe)
|
||||||
|
{
|
||||||
|
order.ticksUnderOptimalConditions++;
|
||||||
|
}
|
||||||
|
if (!isTempSafe)
|
||||||
|
{
|
||||||
|
float tempDelta = (ambientTemperature > Props.maxSafeTemperature) ? ambientTemperature - Props.maxSafeTemperature : Props.minSafeTemperature - ambientTemperature;
|
||||||
|
order.temperaturePenaltyPercent = Mathf.Min(1f, order.temperaturePenaltyPercent + tempDelta * Props.penaltyPerDegreePerTick);
|
||||||
|
}
|
||||||
|
if (!hasFuel)
|
||||||
|
{
|
||||||
|
order.productionUntilTick++; // Pause production
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update fuel consumption
|
||||||
|
if (FuelComp != null)
|
||||||
|
{
|
||||||
|
float totalConsumptionRatePerDay = 0f;
|
||||||
|
if(hasFuel)
|
||||||
|
{
|
||||||
|
foreach (var order in producingOrders)
|
||||||
|
{
|
||||||
|
if (order.process.totalNutritionNeeded > 0 && order.process.productionTicks > 0)
|
||||||
|
{
|
||||||
|
totalConsumptionRatePerDay += (order.process.totalNutritionNeeded / order.process.productionTicks) * 60000f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FuelComp.currentConsumptionRate = totalConsumptionRatePerDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish completed orders
|
||||||
|
productionOrders.RemoveAll(order =>
|
||||||
|
{
|
||||||
|
if (order.productionUntilTick > 0 && Find.TickManager.TicksGame >= order.productionUntilTick)
|
||||||
|
{
|
||||||
|
FinishProduction(order);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start new orders
|
||||||
|
int currentlyProducingCount = productionOrders.Count(o => o.productionUntilTick > 0);
|
||||||
|
if (currentlyProducingCount < Props.productionQueueLimit)
|
||||||
|
{
|
||||||
|
var waitingOrder = productionOrders.FirstOrDefault(o => o.productionUntilTick == -1);
|
||||||
|
if (waitingOrder != null)
|
||||||
|
{
|
||||||
|
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
|
||||||
|
int modifiedDelay = (int)(waitingOrder.process.productionTicks / speedFactor);
|
||||||
|
waitingOrder.productionUntilTick = Find.TickManager.TicksGame + modifiedDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private (QualityCategory quality, float baseScore, float penalty) GetEstimatedQualityDetails(QueuedProcessOrder order)
|
||||||
|
{
|
||||||
|
if (order == null || Props.qualityThresholds.NullOrEmpty())
|
||||||
|
{
|
||||||
|
return (QualityCategory.Normal, 0f, 0f);
|
||||||
|
}
|
||||||
|
float progress = (order.process.productionTicks > 0) ? (float)order.ticksUnderOptimalConditions / order.process.productionTicks : 1f;
|
||||||
|
float finalQualityPercent = Mathf.Clamp01(progress - order.temperaturePenaltyPercent);
|
||||||
|
QualityCategory finalQuality = QualityCategory.Awful;
|
||||||
|
foreach (var threshold in Props.qualityThresholds.OrderByDescending(q => q.threshold))
|
||||||
|
{
|
||||||
|
if (finalQualityPercent >= threshold.threshold)
|
||||||
|
{
|
||||||
|
finalQuality = threshold.quality;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (finalQuality, progress, order.temperaturePenaltyPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FinishProduction(QueuedProcessOrder order)
|
||||||
|
{
|
||||||
|
var qualityDetails = GetEstimatedQualityDetails(order);
|
||||||
|
QualityCategory finalQuality = qualityDetails.quality;
|
||||||
|
|
||||||
|
for (int i = 0; i < Props.spawnCount.RandomInRange; i++)
|
||||||
|
{
|
||||||
|
Thing product = ThingMaker.MakeThing(order.process.thingDef);
|
||||||
|
product.TryGetComp<CompQuality>()?.SetQuality(finalQuality, ArtGenerationContext.Colony);
|
||||||
|
GenPlace.TryPlaceThing(product, parent.Position, parent.Map, ThingPlaceMode.Near);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CompInspectStringExtra()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
int producingCount = productionOrders.Count(o => o.productionUntilTick > 0);
|
||||||
|
int queuedCount = productionOrders.Count - producingCount;
|
||||||
|
|
||||||
|
sb.AppendLine($"生产槽位: {producingCount} / {Props.productionQueueLimit}");
|
||||||
|
if (queuedCount > 0) sb.AppendLine($"等待队列: {queuedCount}");
|
||||||
|
|
||||||
|
if (FacilitiesComp != null)
|
||||||
|
{
|
||||||
|
float speedFactor = 1f + FacilitiesComp.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor"));
|
||||||
|
if(speedFactor != 1f) sb.AppendLine($"生产速度: {speedFactor.ToStringPercent()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var producingNow = productionOrders.Where(o => o.productionUntilTick > 0).OrderBy(o => o.productionUntilTick);
|
||||||
|
if (producingNow.Any())
|
||||||
|
{
|
||||||
|
sb.AppendLine("正在生产:");
|
||||||
|
foreach (var order in producingNow)
|
||||||
|
{
|
||||||
|
int remainingTicks = order.productionUntilTick - Find.TickManager.TicksGame;
|
||||||
|
var qualityDetails = GetEstimatedQualityDetails(order);
|
||||||
|
sb.AppendLine($" - {order.process.thingDef.LabelCap}: {remainingTicks.ToStringTicksToPeriod(true, false, true, true)} (品质: {qualityDetails.quality.GetLabel()})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加温度信息
|
||||||
|
string tempStr = "CurrentTemperature".Translate(parent.AmbientTemperature.ToStringTemperature("F0"));
|
||||||
|
tempStr += $" ({"SafeTemperatureRange".Translate()}: {Props.minSafeTemperature.ToStringTemperature("F0")} ~ {Props.maxSafeTemperature.ToStringTemperature("F0")})";
|
||||||
|
sb.AppendLine(tempStr);
|
||||||
|
|
||||||
|
return sb.ToString().TrimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostExposeData()
|
||||||
|
{
|
||||||
|
base.PostExposeData();
|
||||||
|
Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep);
|
||||||
|
Scribe_Deep.Look(ref selectedProcess, "selectedProcess");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||||
|
{
|
||||||
|
foreach (Gizmo gizmo in base.CompGetGizmosExtra())
|
||||||
|
{
|
||||||
|
yield return gizmo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (productionOrders.Any())
|
||||||
|
{
|
||||||
|
var lastOrder = productionOrders.Last();
|
||||||
|
|
||||||
|
yield return new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = "CommandCancelProduction".Translate() + ": " + lastOrder.process.thingDef.LabelCap,
|
||||||
|
defaultDesc = "CommandCancelProductionDesc".Translate(),
|
||||||
|
icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel"),
|
||||||
|
action = () =>
|
||||||
|
{
|
||||||
|
productionOrders.Remove(lastOrder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,20 @@ namespace ArachnaeSwarm
|
|||||||
public List<ThingDef> blacklist;
|
public List<ThingDef> blacklist;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProcessDef
|
public class ProcessDef : IExposable
|
||||||
{
|
{
|
||||||
public ThingDef thingDef;
|
public ThingDef thingDef;
|
||||||
public int productionTicks;
|
public int productionTicks;
|
||||||
public float totalNutritionNeeded;
|
public float totalNutritionNeeded;
|
||||||
|
public ResearchProjectDef requiredResearch;
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_Defs.Look(ref thingDef, "thingDef");
|
||||||
|
Scribe_Values.Look(ref productionTicks, "productionTicks", 0);
|
||||||
|
Scribe_Values.Look(ref totalNutritionNeeded, "totalNutritionNeeded", 0f);
|
||||||
|
Scribe_Defs.Look(ref requiredResearch, "requiredResearch");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QualityThreshold
|
public class QualityThreshold
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class JobDriver_AddProcessToQueue : JobDriver
|
||||||
|
{
|
||||||
|
private const TargetIndex BuildingInd = TargetIndex.A;
|
||||||
|
|
||||||
|
protected Building Building => (Building)job.GetTarget(BuildingInd).Thing;
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
return pawn.Reserve(Building, job, 1, -1, null, errorOnFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
this.FailOnDespawnedNullOrForbidden(BuildingInd);
|
||||||
|
|
||||||
|
yield return Toils_Goto.GotoThing(BuildingInd, PathEndMode.InteractionCell);
|
||||||
|
|
||||||
|
Toil work = ToilMaker.MakeToil("MakeNewToils");
|
||||||
|
work.initAction = delegate
|
||||||
|
{
|
||||||
|
// Call the new component's method
|
||||||
|
Building.GetComp<CompQueuedInteractiveProducer>().AddToQueue();
|
||||||
|
};
|
||||||
|
work.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||||
|
yield return work;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,8 @@
|
|||||||
<Compile Include="ARA_CompInteractiveProducer\CompRefuelableNutrition.cs" />
|
<Compile Include="ARA_CompInteractiveProducer\CompRefuelableNutrition.cs" />
|
||||||
<Compile Include="ARA_CompInteractiveProducer\DataContracts.cs" />
|
<Compile Include="ARA_CompInteractiveProducer\DataContracts.cs" />
|
||||||
<Compile Include="ARA_CompInteractiveProducer\CompTemperatureRuinableDamage.cs" />
|
<Compile Include="ARA_CompInteractiveProducer\CompTemperatureRuinableDamage.cs" />
|
||||||
|
<Compile Include="ARA_CompInteractiveProducer\CompQueuedInteractiveProducer.cs" />
|
||||||
|
<Compile Include="ARA_CompInteractiveProducer\JobDriver_AddProcessToQueue.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ARA_HuggingFace\Hediff_Possession.cs" />
|
<Compile Include="ARA_HuggingFace\Hediff_Possession.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user