暂存
This commit is contained in:
Binary file not shown.
15
1.6/1.6/Defs/Stats/ARA_Stats.xml
Normal file
15
1.6/1.6/Defs/Stats/ARA_Stats.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<StatDef>
|
||||||
|
<defName>ARA_IncubationSpeedFactor</defName>
|
||||||
|
<label>孵化速度</label>
|
||||||
|
<description>应用于孵化池的孵化速度乘数。</description>
|
||||||
|
<category>Building</category>
|
||||||
|
<defaultBaseValue>1</defaultBaseValue>
|
||||||
|
<minValue>0.001</minValue>
|
||||||
|
<toStringStyle>PercentZero</toStringStyle>
|
||||||
|
<showIfUndefined>false</showIfUndefined>
|
||||||
|
</StatDef>
|
||||||
|
|
||||||
|
</Defs>
|
||||||
84
1.6/1.6/Defs/Thing_building/ARA_BioforgeIncubator.xml
Normal file
84
1.6/1.6/Defs/Thing_building/ARA_BioforgeIncubator.xml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<!-- 1. 加成建筑 "孵化加速器" -->
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>ARA_IncubationAccelerator</defName>
|
||||||
|
<label>孵化加速器</label>
|
||||||
|
<description>一个辅助性的生物机械装置,当放置在大型孵化池旁边时,可以加速其内部的孵化过程。</description>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/Misc/ToolCabinet</texPath>
|
||||||
|
<graphicClass>Graphic_Multi</graphicClass>
|
||||||
|
</graphicData>
|
||||||
|
<size>(1,1)</size>
|
||||||
|
<comps>
|
||||||
|
<!-- 使用原版的 CompFacility -->
|
||||||
|
<li Class="CompProperties_Facility">
|
||||||
|
<statOffsets>
|
||||||
|
<!-- 提供我们自定义的孵化速度加成 -->
|
||||||
|
<ARA_IncubationSpeedFactor>0.10</ARA_IncubatingSpeedFactor>
|
||||||
|
</statOffsets>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 2. 主建筑 "生物孵化池" -->
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>ARA_BioforgeIncubator</defName>
|
||||||
|
<label>生物质孵化池</label>
|
||||||
|
<description>一个大型的、需要消耗大量营养物质的孵化设施,可以同时孵化多个单位,并能通过链接外部设备来提高效率。</description>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/Production/BiofuelRefinery</texPath>
|
||||||
|
<graphicClass>Graphic_Multi</graphicClass>
|
||||||
|
<drawSize>(3,3)</drawSize>
|
||||||
|
</graphicData>
|
||||||
|
<size>(3,3)</size>
|
||||||
|
<tickerType>Normal</tickerType>
|
||||||
|
<comps>
|
||||||
|
|
||||||
|
<!-- a. 我们自己的队列生产组件 -->
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_QueuedPawnSpawner">
|
||||||
|
<productionQueueLimit>5</productionQueueLimit>
|
||||||
|
<minNutritionToStart>0.5</minNutritionToStart>
|
||||||
|
<whitelist>
|
||||||
|
<li>ARA_ArachnaeQueen</li>
|
||||||
|
</whitelist>
|
||||||
|
<spawnablePawns>
|
||||||
|
<li>
|
||||||
|
<pawnKind>ArachnaeNode_Race_Drone</pawnKind>
|
||||||
|
<delayTicks>60000</delayTicks>
|
||||||
|
<totalNutritionNeeded>2.0</totalNutritionNeeded>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<pawnKind>ArachnaeNode_Race_Warrior</pawnKind>
|
||||||
|
<delayTicks>90000</delayTicks>
|
||||||
|
<totalNutritionNeeded>5.0</totalNutritionNeeded>
|
||||||
|
<requiredResearch>ARA_AdvancedBiology</requiredResearch>
|
||||||
|
</li>
|
||||||
|
</spawnablePawns>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- b. 我们的营养燃料组件 -->
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
|
||||||
|
<fuelCapacity>20.0</fuelCapacity>
|
||||||
|
<fuelFilter>
|
||||||
|
<categories>
|
||||||
|
<li>FoodMeals</li>
|
||||||
|
<li>AnimalProductRaw</li>
|
||||||
|
</categories>
|
||||||
|
</fuelFilter>
|
||||||
|
<fuelGizmoLabel>营养</fuelGizmoLabel>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- c. 原版的设施链接接收组件 -->
|
||||||
|
<li Class="CompProperties_AffectedByFacilities">
|
||||||
|
<linkableFacilities>
|
||||||
|
<li>ARA_IncubationAccelerator</li>
|
||||||
|
</linkableFacilities>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</comps>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
</Defs>
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
|
||||||
|
// CompProperties: 在XML中配置组件的属性
|
||||||
|
public class CompProperties_QueuedPawnSpawner : CompProperties
|
||||||
|
{
|
||||||
|
public List<QueuedPawnSpawnEntry> spawnablePawns;
|
||||||
|
public List<PawnKindDef> whitelist;
|
||||||
|
public int productionQueueLimit = 1;
|
||||||
|
public float minNutritionToStart = 0.1f;
|
||||||
|
|
||||||
|
public CompProperties_QueuedPawnSpawner()
|
||||||
|
{
|
||||||
|
compClass = typeof(CompQueuedPawnSpawner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主组件类
|
||||||
|
public class CompQueuedPawnSpawner : ThingComp
|
||||||
|
{
|
||||||
|
private List<QueuedProductionOrder> productionOrders = new List<QueuedProductionOrder>();
|
||||||
|
|
||||||
|
// 缓存对其他组件的引用以提高性能
|
||||||
|
private CompRefuelableNutrition _fuelComp;
|
||||||
|
private CompAffectedByFacilities _facilitiesComp;
|
||||||
|
|
||||||
|
public CompProperties_QueuedPawnSpawner Props => (CompProperties_QueuedPawnSpawner)props;
|
||||||
|
|
||||||
|
private CompRefuelableNutrition FuelComp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_fuelComp == null) _fuelComp = parent.GetComp<CompRefuelableNutrition>();
|
||||||
|
return _fuelComp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private CompAffectedByFacilities FacilitiesComp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_facilitiesComp == null) _facilitiesComp = parent.GetComp<CompAffectedByFacilities>();
|
||||||
|
return _facilitiesComp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(CompProperties props)
|
||||||
|
{
|
||||||
|
base.Initialize(props);
|
||||||
|
// 在初始化时获取一次,避免在每次访问时都调用GetComp
|
||||||
|
_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() + ": " + "NoFuel".Translate(), null);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (QueuedPawnSpawnEntry entry in Props.spawnablePawns)
|
||||||
|
{
|
||||||
|
if (entry.pawnKind == null) continue;
|
||||||
|
|
||||||
|
if (entry.requiredResearch != null && !entry.requiredResearch.IsFinished)
|
||||||
|
{
|
||||||
|
string disabledText = "ARA_Incubate".Translate(entry.pawnKind.label) + " (" + "Requires".Translate() + ": " + entry.requiredResearch.label + ")";
|
||||||
|
yield return new FloatMenuOption(disabledText, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string label = "ARA_Incubate".Translate(entry.pawnKind.label);
|
||||||
|
if (entry.totalNutritionNeeded > 0)
|
||||||
|
{
|
||||||
|
label += $" ({"NutritionNeeded".Translate()}: {entry.totalNutritionNeeded.ToString("0.0")})";
|
||||||
|
}
|
||||||
|
yield return new FloatMenuOption(label, () => AddToQueue(entry, selPawn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToQueue(QueuedPawnSpawnEntry entry, Pawn selPawn)
|
||||||
|
{
|
||||||
|
productionOrders.Add(new QueuedProductionOrder { entry = entry });
|
||||||
|
// 给交互的Pawn一个反馈,表示订单已接受
|
||||||
|
if (selPawn.jobs?.curJob != null)
|
||||||
|
{
|
||||||
|
selPawn.jobs.EndCurrentJob(JobCondition.Succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CompTick()
|
||||||
|
{
|
||||||
|
base.CompTick();
|
||||||
|
|
||||||
|
var producingOrders = productionOrders.Where(o => o.spawnUntilTick > 0).ToList();
|
||||||
|
bool hasFuel = FuelComp?.HasFuel ?? true;
|
||||||
|
|
||||||
|
// 处理无燃料情况:仅暂停生产
|
||||||
|
if (!hasFuel && FuelComp != null && producingOrders.Any())
|
||||||
|
{
|
||||||
|
foreach (var order in producingOrders)
|
||||||
|
{
|
||||||
|
order.spawnUntilTick++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态计算总燃料消耗速率
|
||||||
|
if (FuelComp != null)
|
||||||
|
{
|
||||||
|
float totalConsumptionRatePerDay = 0f;
|
||||||
|
// 只计算有燃料时正在生产的订单
|
||||||
|
if(hasFuel)
|
||||||
|
{
|
||||||
|
foreach (var order in producingOrders)
|
||||||
|
{
|
||||||
|
if (order.entry.totalNutritionNeeded > 0 && order.entry.delayTicks > 0)
|
||||||
|
{
|
||||||
|
totalConsumptionRatePerDay += (order.entry.totalNutritionNeeded / order.entry.delayTicks) * 60000f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FuelComp.currentConsumptionRate = totalConsumptionRatePerDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查并完成订单
|
||||||
|
productionOrders.RemoveAll(order =>
|
||||||
|
{
|
||||||
|
if (order.spawnUntilTick > 0 && Find.TickManager.TicksGame >= order.spawnUntilTick)
|
||||||
|
{
|
||||||
|
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(order.entry.pawnKind, parent.Faction));
|
||||||
|
if (pawn != null) GenPlace.TryPlaceThing(pawn, parent.Position, parent.Map, ThingPlaceMode.Near);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查并启动新订单
|
||||||
|
int currentlyProducingCount = productionOrders.Count(o => o.spawnUntilTick > 0);
|
||||||
|
if (currentlyProducingCount < Props.productionQueueLimit)
|
||||||
|
{
|
||||||
|
QueuedProductionOrder waitingOrder = productionOrders.FirstOrDefault(o => o.spawnUntilTick == -1);
|
||||||
|
if (waitingOrder != null)
|
||||||
|
{
|
||||||
|
float speedFactor = 1f;
|
||||||
|
if (FacilitiesComp != null)
|
||||||
|
{
|
||||||
|
speedFactor += FacilitiesComp.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor"));
|
||||||
|
}
|
||||||
|
int modifiedDelay = (int)(waitingOrder.entry.delayTicks / speedFactor);
|
||||||
|
waitingOrder.spawnUntilTick = Find.TickManager.TicksGame + modifiedDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CompInspectStringExtra()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (FuelComp != null) sb.AppendLine(FuelComp.CompInspectStringExtra());
|
||||||
|
|
||||||
|
int producingCount = productionOrders.Count(o => o.spawnUntilTick > 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.spawnUntilTick > 0).OrderBy(o => o.spawnUntilTick);
|
||||||
|
if (producingNow.Any())
|
||||||
|
{
|
||||||
|
sb.AppendLine("正在孵化:");
|
||||||
|
foreach (var order in producingNow)
|
||||||
|
{
|
||||||
|
int remainingTicks = order.spawnUntilTick - Find.TickManager.TicksGame;
|
||||||
|
sb.AppendLine($" - {order.entry.pawnKind.LabelCap}: {remainingTicks.ToStringTicksToPeriod(true, false, true, true)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString().TrimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostExposeData()
|
||||||
|
{
|
||||||
|
base.PostExposeData();
|
||||||
|
Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep, new object[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
// 重命名以避免冲突
|
||||||
|
public class QueuedPawnSpawnEntry : IExposable
|
||||||
|
{
|
||||||
|
public PawnKindDef pawnKind;
|
||||||
|
public int delayTicks = 0;
|
||||||
|
public ResearchProjectDef requiredResearch;
|
||||||
|
public float totalNutritionNeeded = 0f;
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_Defs.Look(ref pawnKind, "pawnKind");
|
||||||
|
Scribe_Values.Look(ref delayTicks, "delayTicks", 0);
|
||||||
|
Scribe_Defs.Look(ref requiredResearch, "requiredResearch");
|
||||||
|
Scribe_Values.Look(ref totalNutritionNeeded, "totalNutritionNeeded", 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重命名以避免冲突
|
||||||
|
public class QueuedProductionOrder : IExposable
|
||||||
|
{
|
||||||
|
public QueuedPawnSpawnEntry entry;
|
||||||
|
public int spawnUntilTick = -1;
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
if (Scribe.mode == LoadSaveMode.Saving || Scribe.mode == LoadSaveMode.LoadingVars)
|
||||||
|
{
|
||||||
|
if (Scribe.EnterNode("entry"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (entry == null) entry = new QueuedPawnSpawnEntry();
|
||||||
|
entry.ExposeData();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Scribe.ExitNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,8 @@
|
|||||||
<Compile Include="ARA_SpawnPawnFromList\CompProperties_SpawnPawnFromList.cs" />
|
<Compile Include="ARA_SpawnPawnFromList\CompProperties_SpawnPawnFromList.cs" />
|
||||||
<Compile Include="ARA_SpawnPawnFromList\CompSpawnPawnFromList.cs" />
|
<Compile Include="ARA_SpawnPawnFromList\CompSpawnPawnFromList.cs" />
|
||||||
<Compile Include="ARA_SpawnPawnFromList\JobDriver_Incubate.cs" />
|
<Compile Include="ARA_SpawnPawnFromList\JobDriver_Incubate.cs" />
|
||||||
|
<Compile Include="ARA_SpawnPawnFromList\CompQueuedPawnSpawner.cs" />
|
||||||
|
<Compile Include="ARA_SpawnPawnFromList\ProductionContracts.cs" />
|
||||||
<Compile Include="ARA_QueenAbility\CompProperties_AbilitySprayLiquidMulti.cs" />
|
<Compile Include="ARA_QueenAbility\CompProperties_AbilitySprayLiquidMulti.cs" />
|
||||||
<Compile Include="ARA_QueenAbility\CompAbilityEffect_SprayLiquidMulti.cs" />
|
<Compile Include="ARA_QueenAbility\CompAbilityEffect_SprayLiquidMulti.cs" />
|
||||||
<Compile Include="DRM_HediffCurseFlame\Hediff_CurseFlame.cs" />
|
<Compile Include="DRM_HediffCurseFlame\Hediff_CurseFlame.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user