zc
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -487,6 +487,18 @@
|
||||
<li>ARA_Technology_2NPT</li>
|
||||
</prerequisites>
|
||||
</ResearchProjectDef>
|
||||
<ResearchProjectDef ParentName="ARA_techBase">
|
||||
<defName>ARA_Technology_4NPT</defName>
|
||||
<label>节点NPT-4"孵化池"</label>
|
||||
<description><color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许虫族建造孵化池。一种专用于批量生产虫族的孵化场地。孵化池的孵化效率比孵化茧更高。</description>
|
||||
<baseCost>1800</baseCost>
|
||||
<researchViewX>12.00</researchViewX>
|
||||
<researchViewY>2.10</researchViewY>
|
||||
<requiredResearchBuilding>ARA_ResearchBench</requiredResearchBuilding> <!-- ARA_MorphableResearchBench-->
|
||||
<prerequisites>
|
||||
<li>ARA_Technology_1NPT</li>
|
||||
</prerequisites>
|
||||
</ResearchProjectDef>
|
||||
<!-- 作物发展 -->
|
||||
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
|
||||
<defName>ARA_Technology_8CPE</defName>
|
||||
|
||||
@@ -701,89 +701,124 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps>
|
||||
<!-- a. 我们自己的队列生产组件 (带通量控制) -->
|
||||
<!-- a. 队列生产组件 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_QueuedPawnSpawnerWithFlux">
|
||||
<productionQueueLimit>5</productionQueueLimit>
|
||||
<minNutritionToStart>0.5</minNutritionToStart>
|
||||
<whitelist>
|
||||
<li>ArachnaeBase_Race_Larva</li>
|
||||
</whitelist>
|
||||
</li>
|
||||
|
||||
<!-- 质量系统设置 -->
|
||||
<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>
|
||||
|
||||
<spawnablePawns>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
|
||||
<delayTicks>240000</delayTicks>
|
||||
<totalNutritionNeeded>100.0</totalNutritionNeeded>
|
||||
</li>
|
||||
<!-- b. 孵化配置数据组件(提供可孵化单位列表) -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_IncubatorData">
|
||||
<incubationConfigs>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_ShieldHead</pawnKind>
|
||||
<delayTicks>180000</delayTicks>
|
||||
<totalNutritionNeeded>40.0</totalNutritionNeeded>
|
||||
<daysRequired>3</daysRequired>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_WeaponSmith</pawnKind>
|
||||
<delayTicks>180000</delayTicks>
|
||||
<totalNutritionNeeded>40.0</totalNutritionNeeded>
|
||||
<daysRequired>3</daysRequired>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Fighter</pawnKind>
|
||||
<delayTicks>90000</delayTicks>
|
||||
<totalNutritionNeeded>20.0</totalNutritionNeeded>
|
||||
<daysRequired>1.5</daysRequired>
|
||||
<requiredResearch>ARA_Technology_1KYC</requiredResearch>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
|
||||
<daysRequired>4</daysRequired>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Smokepop</pawnKind>
|
||||
<delayTicks>180000</delayTicks>
|
||||
<totalNutritionNeeded>60.0</totalNutritionNeeded>
|
||||
<daysRequired>3</daysRequired>
|
||||
<requiredResearch>ARA_Technology_5KYC</requiredResearch>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Skyraider</pawnKind>
|
||||
<delayTicks>120000</delayTicks>
|
||||
<totalNutritionNeeded>80.0</totalNutritionNeeded>
|
||||
<daysRequired>2</daysRequired>
|
||||
<requiredResearch>ARA_Technology_2KYC</requiredResearch>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ARA_MimicNematodeShamblerSwarmer</pawnKind>
|
||||
<delayTicks>600</delayTicks>
|
||||
<totalNutritionNeeded>10.0</totalNutritionNeeded>
|
||||
<daysRequired>0.01</daysRequired>
|
||||
<requiredResearch>ARA_Technology_6MEN</requiredResearch>
|
||||
<extraHediffs>
|
||||
<li>ARA_Incubator_1_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_2_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_3_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_4_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_5_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_6_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_7_Reward_Hediffs</li>
|
||||
<li>ARA_Incubator_8_Reward_Hediffs</li>
|
||||
</extraHediffs>
|
||||
</li>
|
||||
</spawnablePawns>
|
||||
</incubationConfigs>
|
||||
</li>
|
||||
|
||||
<!-- b. 我们的营养燃料组件 -->
|
||||
<!-- c. 营养燃料组件 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
|
||||
<fuelCapacity>300.0</fuelCapacity>
|
||||
<fuelFilter>
|
||||
@@ -796,7 +831,7 @@
|
||||
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
||||
</li>
|
||||
|
||||
<!-- c. 原版的设施链接接收组件 -->
|
||||
<!-- d. 设施链接组件 -->
|
||||
<li Class="CompProperties_AffectedByFacilities">
|
||||
<linkableFacilities>
|
||||
<li>ARA_NutrientNetworkTower</li>
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<Compile Include="Buildings\Building_Incubatable.cs" />
|
||||
<Compile Include="Buildings\IFluxController.cs" />
|
||||
<Compile Include="Buildings\ILarvaActivatable.cs" />
|
||||
<Compile Include="Buildings\IncubatorUtils.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\Building_Ootheca.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\CompProperties_IncubatorData.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\Gizmo_IncubationProgress.cs" />
|
||||
|
||||
@@ -401,6 +401,8 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowOrderMenuPublic() => ShowOrderMenu();
|
||||
|
||||
private void ShowOrderMenu()
|
||||
{
|
||||
var options = new List<FloatMenuOption>();
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace ArachnaeSwarm
|
||||
// 订单状态
|
||||
public enum OrderStatus
|
||||
{
|
||||
WaitingForLarva = 0, // 等待幼虫激活
|
||||
Incubating = 1, // 正在孵化
|
||||
WaitingForLarva = 0,
|
||||
Incubating = 1,
|
||||
}
|
||||
|
||||
// 用于 Gizmo 显示的订单信息
|
||||
@@ -25,10 +25,10 @@ namespace ArachnaeSwarm
|
||||
public string estimatedQuality;
|
||||
}
|
||||
|
||||
// 带状态和品质的订单
|
||||
// 带状态和品质的督虫订单
|
||||
public class QueuedPawnOrder : IExposable
|
||||
{
|
||||
public QueuedPawnSpawnEntry entry;
|
||||
public IncubationConfig config; // 使用 IncubationConfig 而不是 QueuedPawnSpawnEntry
|
||||
public OrderStatus status = OrderStatus.WaitingForLarva;
|
||||
public int spawnUntilTick = -1;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace ArachnaeSwarm
|
||||
|
||||
public void ExposeData()
|
||||
{
|
||||
Scribe_Deep.Look(ref entry, "entry");
|
||||
Scribe_Deep.Look(ref config, "config");
|
||||
Scribe_Values.Look(ref status, "status", OrderStatus.WaitingForLarva);
|
||||
Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1);
|
||||
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
|
||||
@@ -50,15 +50,11 @@ namespace ArachnaeSwarm
|
||||
|
||||
public class CompProperties_QueuedPawnSpawnerWithFlux : CompProperties
|
||||
{
|
||||
public List<QueuedPawnSpawnEntry> spawnablePawns;
|
||||
public List<PawnKindDef> whitelist;
|
||||
public List<PawnKindDef> whitelist; // 允许激活的 pawn 类型(幼虫)
|
||||
public int productionQueueLimit = 5;
|
||||
public float minNutritionToStart = 0.1f;
|
||||
|
||||
// 质量系统
|
||||
public float minSafeTemperature = 7f;
|
||||
public float maxSafeTemperature = 32f;
|
||||
public float penaltyPerDegreePerTick = 0.00001f;
|
||||
public List<QualityThreshold> qualityThresholds;
|
||||
|
||||
public CompProperties_QueuedPawnSpawnerWithFlux()
|
||||
@@ -82,10 +78,15 @@ namespace ArachnaeSwarm
|
||||
// === 组件引用 ===
|
||||
private CompRefuelableNutrition _fuelComp;
|
||||
private CompAffectedByFacilities _facilitiesComp;
|
||||
private CompIncubatorData _incubatorDataComp;
|
||||
|
||||
public CompProperties_QueuedPawnSpawnerWithFlux Props => (CompProperties_QueuedPawnSpawnerWithFlux)props;
|
||||
private CompRefuelableNutrition FuelComp => _fuelComp ?? (_fuelComp = parent.GetComp<CompRefuelableNutrition>());
|
||||
private CompAffectedByFacilities FacilitiesComp => _facilitiesComp ?? (_facilitiesComp = parent.GetComp<CompAffectedByFacilities>());
|
||||
private CompIncubatorData IncubatorDataComp => _incubatorDataComp ?? (_incubatorDataComp = parent.GetComp<CompIncubatorData>());
|
||||
|
||||
// 获取可孵化配置列表(从 CompIncubatorData)
|
||||
public List<IncubationConfig> IncubationConfigs => IncubatorDataComp?.IncubationConfigs ?? new List<IncubationConfig>();
|
||||
|
||||
// === IFluxController 接口实现 ===
|
||||
public float NeutronFlux => neutronFlux;
|
||||
@@ -120,17 +121,18 @@ namespace ArachnaeSwarm
|
||||
base.Initialize(props);
|
||||
_fuelComp = parent.GetComp<CompRefuelableNutrition>();
|
||||
_facilitiesComp = parent.GetComp<CompAffectedByFacilities>();
|
||||
_incubatorDataComp = parent.GetComp<CompIncubatorData>();
|
||||
}
|
||||
|
||||
// === 订单管理 ===
|
||||
public void AddOrder(QueuedPawnSpawnEntry entry)
|
||||
public void AddOrder(IncubationConfig config)
|
||||
{
|
||||
if (orders.Count >= Props.productionQueueLimit)
|
||||
{
|
||||
Messages.Message("队列已满!", MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
orders.Add(new QueuedPawnOrder { entry = entry, status = OrderStatus.WaitingForLarva });
|
||||
orders.Add(new QueuedPawnOrder { config = config, status = OrderStatus.WaitingForLarva });
|
||||
}
|
||||
|
||||
public void RemoveOrder(QueuedPawnOrder order) => orders.Remove(order);
|
||||
@@ -148,14 +150,14 @@ namespace ArachnaeSwarm
|
||||
float prodProgress = GetProgress(order);
|
||||
result.Add(new PawnOrderDisplayInfo
|
||||
{
|
||||
label = order.entry.pawnKind.LabelCap,
|
||||
label = order.config?.pawnKind?.LabelCap ?? "?",
|
||||
status = order.status,
|
||||
progress = prodProgress,
|
||||
qualityProgress = order.QualityPercent,
|
||||
remainingTime = order.status == OrderStatus.Incubating && order.spawnUntilTick > 0
|
||||
? (order.spawnUntilTick - Find.TickManager.TicksGame).ToStringTicksToPeriod()
|
||||
: "等待中",
|
||||
estimatedQuality = GetEstimatedQuality(order).GetLabel()
|
||||
estimatedQuality = GetEstimatedQuality(order.QualityPercent)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
@@ -163,24 +165,21 @@ namespace ArachnaeSwarm
|
||||
|
||||
private float GetProgress(QueuedPawnOrder order)
|
||||
{
|
||||
if (order.status != OrderStatus.Incubating || order.spawnUntilTick <= 0) return 0f;
|
||||
int totalTicks = order.entry.delayTicks;
|
||||
if (order.status != OrderStatus.Incubating || order.spawnUntilTick <= 0 || order.config == null) return 0f;
|
||||
int totalTicks = Mathf.RoundToInt(order.config.daysRequired * 60000);
|
||||
int startTick = order.spawnUntilTick - totalTicks;
|
||||
int elapsed = Find.TickManager.TicksGame - startTick;
|
||||
return totalTicks > 0 ? Mathf.Clamp01((float)elapsed / totalTicks) : 0f;
|
||||
}
|
||||
|
||||
private QualityCategory GetEstimatedQuality(QueuedPawnOrder order)
|
||||
private string GetEstimatedQuality(float qualityPercent)
|
||||
{
|
||||
if (Props.qualityThresholds.NullOrEmpty()) return QualityCategory.Normal;
|
||||
float qualityPercent = order.QualityPercent;
|
||||
foreach (var threshold in Props.qualityThresholds.OrderByDescending(q => q.threshold))
|
||||
{
|
||||
if (qualityPercent >= threshold.threshold) return threshold.quality;
|
||||
}
|
||||
return Props.qualityThresholds.Any()
|
||||
? Props.qualityThresholds.OrderBy(q => q.threshold).First().quality
|
||||
: QualityCategory.Awful;
|
||||
if (qualityPercent >= 0.99f) return "传奇";
|
||||
if (qualityPercent >= 0.90f) return "杰作";
|
||||
if (qualityPercent >= 0.70f) return "优秀";
|
||||
if (qualityPercent >= 0.50f) return "良好";
|
||||
if (qualityPercent >= 0.20f) return "普通";
|
||||
return "较差";
|
||||
}
|
||||
|
||||
// === 幼虫激活逻辑 ===
|
||||
@@ -194,9 +193,14 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
int called = 0;
|
||||
var availableLarvae = FindAvailableLarvae(neededLarvae);
|
||||
int found = 0;
|
||||
var availableLarvae = FindAvailableLarvae(neededLarvae * 2);
|
||||
found = availableLarvae.Count;
|
||||
|
||||
foreach (var larva in availableLarvae)
|
||||
{
|
||||
if (called >= neededLarvae) break;
|
||||
|
||||
var job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_OperateIncubator"), parent);
|
||||
if (larva.jobs.TryTakeOrderedJob(job, JobTag.Misc))
|
||||
{
|
||||
@@ -206,28 +210,32 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
if (called > 0)
|
||||
Messages.Message($"已呼叫 {called} 只幼虫", MessageTypeDefOf.PositiveEvent);
|
||||
Messages.Message($"已呼叫 {called} 只幼虫 (找到{found}只)", MessageTypeDefOf.PositiveEvent);
|
||||
else
|
||||
Messages.Message("未找到可用的幼虫!", MessageTypeDefOf.RejectInput);
|
||||
Messages.Message($"未找到可用的幼虫! (需要{neededLarvae}只,找到{found}只)", MessageTypeDefOf.RejectInput);
|
||||
}
|
||||
|
||||
private List<Pawn> FindAvailableLarvae(int maxCount)
|
||||
{
|
||||
var result = new List<Pawn>();
|
||||
float searchRadius = 50f;
|
||||
if (parent.Map == null) return result;
|
||||
|
||||
foreach (var pawn in parent.Map.mapPawns.AllPawnsSpawned)
|
||||
{
|
||||
if (result.Count >= maxCount) break;
|
||||
if (pawn.def.defName == "ArachnaeBase_Race_Larva" &&
|
||||
!pawn.Downed && !pawn.Dead &&
|
||||
pawn.Faction == parent.Faction &&
|
||||
!assignedLarvae.Contains(pawn) &&
|
||||
parent.Position.DistanceTo(pawn.Position) <= searchRadius)
|
||||
{
|
||||
result.Add(pawn);
|
||||
}
|
||||
|
||||
if (pawn.def.defName != "ArachnaeBase_Race_Larva") continue;
|
||||
if (pawn.Downed || pawn.Dead) continue;
|
||||
if (pawn.Faction != parent.Faction) continue;
|
||||
if (assignedLarvae.Contains(pawn)) continue;
|
||||
|
||||
bool isBusy = pawn.CurJobDef != null &&
|
||||
pawn.CurJobDef != JobDefOf.Wait_Wander &&
|
||||
pawn.CurJobDef != JobDefOf.GotoWander &&
|
||||
pawn.CurJobDef.defName != "Wait";
|
||||
if (isBusy) continue;
|
||||
|
||||
result.Add(pawn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -237,11 +245,12 @@ namespace ArachnaeSwarm
|
||||
public void NotifyLarvaOperationComplete(Pawn larva)
|
||||
{
|
||||
var waitingOrder = orders.FirstOrDefault(o => o.status == OrderStatus.WaitingForLarva);
|
||||
if (waitingOrder != null)
|
||||
if (waitingOrder != null && waitingOrder.config != null)
|
||||
{
|
||||
waitingOrder.status = OrderStatus.Incubating;
|
||||
waitingOrder.spawnUntilTick = Find.TickManager.TicksGame + waitingOrder.entry.delayTicks;
|
||||
waitingOrder.qualityTotal = waitingOrder.entry.delayTicks;
|
||||
int totalTicks = Mathf.RoundToInt(waitingOrder.config.daysRequired * 60000);
|
||||
waitingOrder.spawnUntilTick = Find.TickManager.TicksGame + totalTicks;
|
||||
waitingOrder.qualityTotal = totalTicks;
|
||||
waitingOrder.qualityProgress = 0f;
|
||||
}
|
||||
assignedLarvae.Remove(larva);
|
||||
@@ -254,22 +263,19 @@ namespace ArachnaeSwarm
|
||||
|
||||
assignedLarvae.RemoveAll(l => l == null || l.Dead || l.Destroyed);
|
||||
|
||||
bool hasFuel = FuelComp?.HasFuel ?? true;
|
||||
bool hasFuel = (FuelComp?.Fuel ?? 10f) > 0.01f;
|
||||
|
||||
// 自动模式调节
|
||||
if (IsAutoMode && parent.IsHashIntervalTick(250) && IsIncubating)
|
||||
{
|
||||
CalculateAutoFlux();
|
||||
}
|
||||
|
||||
// 消耗燃料
|
||||
if (IsIncubating && FuelComp != null && neutronFlux > 0.01f)
|
||||
{
|
||||
float fuelPerTick = (50f * FluxEfficiency * IncubatingCount) / 60000f;
|
||||
FuelComp.ConsumeFuel(fuelPerTick);
|
||||
}
|
||||
|
||||
// 处理正在孵化的订单
|
||||
if (hasFuel && !IsDormant)
|
||||
{
|
||||
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
|
||||
@@ -277,7 +283,6 @@ namespace ArachnaeSwarm
|
||||
|
||||
foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating))
|
||||
{
|
||||
// 进度推进
|
||||
float extraProgress = fluxSpeed - 1f;
|
||||
if (extraProgress > 0)
|
||||
{
|
||||
@@ -286,14 +291,12 @@ namespace ArachnaeSwarm
|
||||
order.spawnUntilTick -= extraTicks;
|
||||
}
|
||||
|
||||
// 品质累积(低通量时累积更快)
|
||||
float qualityBonus = 1f + (1f - neutronFlux) * 0.5f;
|
||||
float qualityGain = speedFactor * qualityBonus;
|
||||
order.qualityProgress = Mathf.Min(order.qualityProgress + qualityGain, order.qualityTotal);
|
||||
}
|
||||
}
|
||||
|
||||
// 完成订单
|
||||
orders.RemoveAll(order =>
|
||||
{
|
||||
if (order.status == OrderStatus.Incubating &&
|
||||
@@ -309,30 +312,39 @@ namespace ArachnaeSwarm
|
||||
|
||||
private void CompleteOrder(QueuedPawnOrder order)
|
||||
{
|
||||
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(order.entry.pawnKind, parent.Faction));
|
||||
if (order.config?.pawnKind == null) return;
|
||||
|
||||
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(order.config.pawnKind, parent.Faction));
|
||||
if (pawn != null)
|
||||
{
|
||||
// 应用品质效果到 Pawn
|
||||
ApplyQualityEffects(pawn, order.QualityPercent);
|
||||
ApplyQualityEffects(pawn, order.QualityPercent, order.config);
|
||||
GenPlace.TryPlaceThing(pawn, parent.Position, parent.Map, ThingPlaceMode.Near);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyQualityEffects(Pawn pawn, float qualityPercent)
|
||||
private void ApplyQualityEffects(Pawn pawn, float qualityPercent, IncubationConfig config)
|
||||
{
|
||||
// 基于品质百分比调整能力
|
||||
// 0.0 = 最差, 1.0 = 最佳
|
||||
float statBonus = qualityPercent * 0.3f; // 最多+30%
|
||||
|
||||
// 可以在这里添加特定的品质效果
|
||||
// 例如:pawn.health, pawn.skills 等
|
||||
// 应用 Hediff 奖励
|
||||
if (config != null && config.extraHediffs != null)
|
||||
{
|
||||
var rewardHediffs = config.GetRewardHediffs(qualityPercent);
|
||||
if (rewardHediffs != null)
|
||||
{
|
||||
foreach (var hediffDef in rewardHediffs)
|
||||
{
|
||||
if (hediffDef != null)
|
||||
{
|
||||
pawn.health.AddHediff(hediffDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateAutoFlux()
|
||||
{
|
||||
if (fluxMode == FluxMode.Manual) return;
|
||||
|
||||
// 找到品质最低的订单来决定通量
|
||||
var incubating = orders.Where(o => o.status == OrderStatus.Incubating).ToList();
|
||||
if (!incubating.Any()) return;
|
||||
|
||||
@@ -367,13 +379,9 @@ namespace ArachnaeSwarm
|
||||
foreach (var g in base.CompGetGizmosExtra()) yield return g;
|
||||
if (parent.Faction != Faction.OfPlayer) yield break;
|
||||
|
||||
// 通量控制 Gizmo
|
||||
yield return new Gizmo_NeutronFlux(this);
|
||||
|
||||
// 进度 Gizmo
|
||||
yield return new Gizmo_PawnProgressBar(this);
|
||||
|
||||
// 添加订单按钮
|
||||
if (orders.Count < Props.productionQueueLimit)
|
||||
{
|
||||
yield return new Command_Action
|
||||
@@ -385,7 +393,6 @@ namespace ArachnaeSwarm
|
||||
};
|
||||
}
|
||||
|
||||
// 呼叫幼虫按钮
|
||||
int needed = WaitingForLarvaCount - assignedLarvae.Count;
|
||||
if (needed > 0)
|
||||
{
|
||||
@@ -399,26 +406,31 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowOrderMenuPublic() => ShowOrderMenu();
|
||||
|
||||
private void ShowOrderMenu()
|
||||
{
|
||||
var options = new List<FloatMenuOption>();
|
||||
var configs = IncubationConfigs;
|
||||
|
||||
foreach (var entry in Props.spawnablePawns)
|
||||
foreach (var config in configs)
|
||||
{
|
||||
if (entry.requiredResearch != null && !entry.requiredResearch.IsFinished)
|
||||
if (config?.pawnKind == null) continue;
|
||||
|
||||
if (config.requiredResearch != null && !config.requiredResearch.IsFinished)
|
||||
{
|
||||
options.Add(new FloatMenuOption(
|
||||
entry.pawnKind.LabelCap + " (需要研究: " + entry.requiredResearch.LabelCap + ")",
|
||||
config.pawnKind.LabelCap + " (需要研究: " + config.requiredResearch.LabelCap + ")",
|
||||
null
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
var capturedEntry = entry;
|
||||
var capturedConfig = config;
|
||||
options.Add(new FloatMenuOption(
|
||||
entry.pawnKind.LabelCap,
|
||||
config.pawnKind.LabelCap,
|
||||
() => {
|
||||
AddOrder(capturedEntry);
|
||||
AddOrder(capturedConfig);
|
||||
if (orders.Count < Props.productionQueueLimit)
|
||||
ShowOrderMenu();
|
||||
}
|
||||
@@ -429,7 +441,7 @@ namespace ArachnaeSwarm
|
||||
if (options.Count > 0)
|
||||
Find.WindowStack.Add(new FloatMenu(options, "选择孵化目标"));
|
||||
else
|
||||
Messages.Message("没有可用的孵化选项", MessageTypeDefOf.RejectInput);
|
||||
Messages.Message("没有可用的孵化选项(检查 CompIncubatorData 配置)", MessageTypeDefOf.RejectInput);
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
|
||||
@@ -7,16 +7,20 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 双向进度条 Gizmo - 用于物品孵化池
|
||||
/// 从中间向两边生长:左边品质进度,右边生产进度
|
||||
/// 支持滚动显示多个订单
|
||||
/// 样式与旧版 Gizmo_IncubationProgress 统一
|
||||
/// </summary>
|
||||
[StaticConstructorOnStartup]
|
||||
public class Gizmo_DualProgressBar : Gizmo
|
||||
{
|
||||
private const float BarHeight = 22f;
|
||||
private const float Width = 200f;
|
||||
private const float BarHeight = 18f;
|
||||
private const float Spacing = 4f;
|
||||
private const float Padding = 8f;
|
||||
private const float TitleHeight = 26f;
|
||||
private const float MaxVisibleOrders = 4;
|
||||
private const float MaxVisibleOrders = 3;
|
||||
|
||||
private static readonly Texture2D ProgressBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
|
||||
private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
|
||||
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
|
||||
|
||||
private readonly CompQueuedInteractiveProducerWithFlux comp;
|
||||
private float scrollPosition = 0f;
|
||||
@@ -27,7 +31,7 @@ namespace ArachnaeSwarm
|
||||
this.Order = -98f;
|
||||
}
|
||||
|
||||
public override float GetWidth(float maxWidth) => 220f;
|
||||
public override float GetWidth(float maxWidth) => Mathf.Min(Width, maxWidth);
|
||||
|
||||
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
|
||||
{
|
||||
@@ -36,42 +40,68 @@ namespace ArachnaeSwarm
|
||||
|
||||
// 计算高度
|
||||
int visibleCount = Mathf.Min(orderCount, (int)MaxVisibleOrders);
|
||||
float contentHeight = TitleHeight + Spacing;
|
||||
contentHeight += Mathf.Max(1, visibleCount) * (BarHeight + Spacing);
|
||||
contentHeight += Padding;
|
||||
|
||||
float contentHeight = Padding * 2 + Text.LineHeight + Spacing;
|
||||
contentHeight += Mathf.Max(1, visibleCount) * (BarHeight + Spacing + 14f);
|
||||
float totalHeight = Mathf.Max(75f, contentHeight);
|
||||
|
||||
Rect gizmoRect = new Rect(topLeft.x, topLeft.y - (totalHeight - 75f), GetWidth(maxWidth), totalHeight);
|
||||
Widgets.DrawWindowBackground(gizmoRect);
|
||||
Rect rect = new Rect(topLeft.x, topLeft.y - (totalHeight - 75f), GetWidth(maxWidth), totalHeight);
|
||||
Widgets.DrawWindowBackground(rect);
|
||||
|
||||
float curY = gizmoRect.y + Padding;
|
||||
Rect innerRect = rect.ContractedBy(Padding);
|
||||
float curY = innerRect.y;
|
||||
|
||||
// 标题
|
||||
Rect titleRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, TitleHeight);
|
||||
// === 标题区域(可点击打开菜单) ===
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
|
||||
string title = $"孵化进度 ({orderCount}/{comp.Props.productionQueueLimit})";
|
||||
Widgets.Label(titleRect, title);
|
||||
|
||||
curY += TitleHeight + Spacing;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
// 订单列表区域
|
||||
Rect listRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, visibleCount * (BarHeight + Spacing));
|
||||
|
||||
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
|
||||
|
||||
string title;
|
||||
bool canAdd = orderCount < comp.Props.productionQueueLimit;
|
||||
|
||||
if (orderCount > 0)
|
||||
{
|
||||
// 滚动处理
|
||||
if (orderCount > MaxVisibleOrders)
|
||||
title = orders[0].label;
|
||||
if (orderCount > 1) title += $" (+{orderCount - 1})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = "选择生产目标...";
|
||||
}
|
||||
|
||||
if (canAdd)
|
||||
{
|
||||
if (Mouse.IsOver(titleRect))
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing);
|
||||
if (Mouse.IsOver(listRect))
|
||||
{
|
||||
scrollPosition -= Event.current.delta.y * 0.5f;
|
||||
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
|
||||
}
|
||||
Widgets.DrawHighlight(titleRect);
|
||||
}
|
||||
|
||||
if (Widgets.ButtonInvisible(titleRect))
|
||||
{
|
||||
comp.ShowOrderMenuPublic();
|
||||
}
|
||||
|
||||
GUI.color = new Color(0.7f, 0.9f, 1f);
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width - 20f) + " ▼");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = new Color(0.5f, 0.5f, 0.5f);
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width) + " (满)");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
curY += Text.LineHeight + Spacing;
|
||||
|
||||
// === 订单列表 ===
|
||||
if (orderCount > 0)
|
||||
{
|
||||
float listHeight = Mathf.Min(visibleCount, orderCount) * (BarHeight + Spacing + 14f);
|
||||
Rect listRect = new Rect(innerRect.x, curY, innerRect.width, listHeight);
|
||||
|
||||
if (orderCount > MaxVisibleOrders && Mouse.IsOver(listRect))
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing + 14f);
|
||||
scrollPosition -= Event.current.delta.y * 0.5f;
|
||||
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
|
||||
}
|
||||
|
||||
GUI.BeginClip(listRect);
|
||||
@@ -80,103 +110,87 @@ namespace ArachnaeSwarm
|
||||
for (int i = 0; i < orderCount; i++)
|
||||
{
|
||||
var order = orders[i];
|
||||
Rect barRect = new Rect(0, drawY, listRect.width, BarHeight);
|
||||
float itemHeight = BarHeight + 14f;
|
||||
Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight);
|
||||
|
||||
if (barRect.yMax > 0 && barRect.y < listRect.height)
|
||||
if (itemRect.yMax > 0 && itemRect.y < listRect.height)
|
||||
{
|
||||
DrawOrderBar(barRect, order, i);
|
||||
DrawOrderItem(itemRect, order, i);
|
||||
}
|
||||
drawY += BarHeight + Spacing;
|
||||
drawY += itemHeight + Spacing;
|
||||
}
|
||||
|
||||
GUI.EndClip();
|
||||
|
||||
// 滚动条指示
|
||||
if (orderCount > MaxVisibleOrders)
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing);
|
||||
float scrollBarHeight = listRect.height * (MaxVisibleOrders / (float)orderCount);
|
||||
float scrollBarY = curY + (scrollPosition / scrollMax) * (listRect.height - scrollBarHeight);
|
||||
|
||||
Rect scrollBarRect = new Rect(gizmoRect.xMax - 6f, scrollBarY, 4f, scrollBarHeight);
|
||||
Widgets.DrawBoxSolid(scrollBarRect, new Color(1f, 1f, 1f, 0.3f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect emptyRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, BarHeight);
|
||||
Text.Font = GameFont.Tiny;
|
||||
GUI.color = Color.gray;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(emptyRect, "无订单 - 点击添加");
|
||||
GUI.color = new Color(0.7f, 0.7f, 0.7f);
|
||||
Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), "就绪 - 点击上方选择目标");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
return new GizmoResult(GizmoState.Clear);
|
||||
}
|
||||
|
||||
private void DrawOrderBar(Rect rect, OrderDisplayInfo order, int index)
|
||||
private void DrawOrderItem(Rect rect, OrderDisplayInfo order, int index)
|
||||
{
|
||||
// 背景
|
||||
Widgets.DrawBoxSolid(rect, new Color(0.08f, 0.08f, 0.1f, 0.9f));
|
||||
|
||||
float labelHeight = 14f;
|
||||
|
||||
Text.Font = GameFont.Tiny;
|
||||
Rect labelRect = new Rect(rect.x, rect.y, rect.width - 20f, labelHeight);
|
||||
|
||||
if (order.status == OrderStatus.WaitingForLarva)
|
||||
{
|
||||
// 等待幼虫状态 - 显示标签
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleLeft;
|
||||
Rect labelRect = new Rect(rect.x + 4f, rect.y, rect.width - 28f, rect.height);
|
||||
GUI.color = new Color(1f, 0.8f, 0.4f);
|
||||
Widgets.Label(labelRect, $"🐛 {order.label} [等待幼虫]");
|
||||
GUI.color = Color.white;
|
||||
Widgets.Label(labelRect, $"{order.label} [等待幼虫]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正在孵化 - 双向进度条
|
||||
float midX = rect.x + rect.width / 2f;
|
||||
float halfWidth = (rect.width - 28f) / 2f; // 留出取消按钮空间
|
||||
|
||||
// 品质进度(向左生长,青色)
|
||||
float qualityWidth = halfWidth * order.qualityProgress;
|
||||
Rect qualityRect = new Rect(midX - qualityWidth, rect.y + 2f, qualityWidth, rect.height - 4f);
|
||||
Color qualityColor = Color.Lerp(new Color(0.2f, 0.5f, 0.6f), new Color(0.3f, 0.8f, 0.9f), order.qualityProgress);
|
||||
Widgets.DrawBoxSolid(qualityRect, qualityColor);
|
||||
|
||||
// 生产进度(向右生长,绿色)
|
||||
float progressWidth = halfWidth * order.productionProgress;
|
||||
Rect progressRect = new Rect(midX, rect.y + 2f, progressWidth, rect.height - 4f);
|
||||
Color progressColor = Color.Lerp(new Color(0.3f, 0.5f, 0.3f), new Color(0.4f, 0.9f, 0.4f), order.productionProgress);
|
||||
Widgets.DrawBoxSolid(progressRect, progressColor);
|
||||
|
||||
// 中线
|
||||
Widgets.DrawLineVertical(midX, rect.y + 2f, rect.height - 4f);
|
||||
|
||||
// 标签
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Rect labelRect = new Rect(rect.x, rect.y, rect.width - 24f, rect.height);
|
||||
string displayText = $"{order.label} {order.productionProgress.ToStringPercent("F0")}";
|
||||
GUI.color = Color.white;
|
||||
Widgets.Label(labelRect, displayText);
|
||||
|
||||
// 品质提示
|
||||
string tooltip = $"{order.label}\n生产进度: {order.productionProgress.ToStringPercent()}\n品质进度: {order.qualityProgress.ToStringPercent()}\n预计品质: {order.estimatedQuality}";
|
||||
TooltipHandler.TipRegion(rect, tooltip);
|
||||
Widgets.Label(labelRect, $"{order.label} {order.productionProgress.ToStringPercent("F0")}");
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
|
||||
// 取消按钮(右侧X)
|
||||
Rect cancelRect = new Rect(rect.xMax - 20f, rect.y + 2f, 18f, rect.height - 4f);
|
||||
if (Widgets.ButtonText(cancelRect, "X", false))
|
||||
Rect cancelRect = new Rect(rect.xMax - 16f, rect.y, 16f, labelHeight);
|
||||
if (Widgets.ButtonText(cancelRect, "×", false))
|
||||
{
|
||||
comp.RemoveOrderByIndex(index);
|
||||
}
|
||||
|
||||
// 边框
|
||||
Widgets.DrawBox(rect);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
Rect barRect = new Rect(rect.x, rect.y + labelHeight, rect.width, BarHeight);
|
||||
|
||||
if (order.status == OrderStatus.Incubating)
|
||||
{
|
||||
float midX = barRect.x + barRect.width / 2f;
|
||||
float halfWidth = barRect.width / 2f;
|
||||
|
||||
GUI.DrawTexture(barRect, EmptyBarTex);
|
||||
|
||||
float qualityWidth = halfWidth * order.qualityProgress;
|
||||
Rect qualityRect = new Rect(midX - qualityWidth, barRect.y, qualityWidth, barRect.height);
|
||||
GUI.DrawTexture(qualityRect, QualityBarTex);
|
||||
|
||||
float progressWidth = halfWidth * order.productionProgress;
|
||||
Rect progressRect = new Rect(midX, barRect.y, progressWidth, barRect.height);
|
||||
GUI.DrawTexture(progressRect, ProgressBarTex);
|
||||
|
||||
Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
|
||||
|
||||
string tooltip = $"{order.label}\n品质: {order.qualityProgress.ToStringPercent()} → {order.estimatedQuality}\n进度: {order.productionProgress.ToStringPercent()}";
|
||||
TooltipHandler.TipRegion(barRect, tooltip);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawTexture(barRect, EmptyBarTex);
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.8f, 0.6f, 0.2f);
|
||||
Widgets.Label(barRect, "等待幼虫激活");
|
||||
GUI.color = Color.white;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,20 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 双向进度条 Gizmo - 用于督虫孵化池
|
||||
/// 从中间向两边生长:左边品质进度,右边生产进度
|
||||
/// 支持滚动显示多个订单
|
||||
/// 样式与旧版 Gizmo_IncubationProgress 统一
|
||||
/// </summary>
|
||||
[StaticConstructorOnStartup]
|
||||
public class Gizmo_PawnProgressBar : Gizmo
|
||||
{
|
||||
private const float BarHeight = 22f;
|
||||
private const float Width = 200f;
|
||||
private const float BarHeight = 18f;
|
||||
private const float Spacing = 4f;
|
||||
private const float Padding = 8f;
|
||||
private const float TitleHeight = 26f;
|
||||
private const float MaxVisibleOrders = 4;
|
||||
private const float MaxVisibleOrders = 3;
|
||||
|
||||
private static readonly Texture2D ProgressBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.7f, 0.2f, 0.8f));
|
||||
private static readonly Texture2D QualityBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.5f, 0.9f, 0.8f));
|
||||
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.5f));
|
||||
|
||||
private readonly CompQueuedPawnSpawnerWithFlux comp;
|
||||
private float scrollPosition = 0f;
|
||||
@@ -27,48 +31,81 @@ namespace ArachnaeSwarm
|
||||
this.Order = -98f;
|
||||
}
|
||||
|
||||
public override float GetWidth(float maxWidth) => 220f;
|
||||
public override float GetWidth(float maxWidth) => Mathf.Min(Width, maxWidth);
|
||||
|
||||
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
|
||||
{
|
||||
var orders = comp.GetOrdersForGizmo();
|
||||
int orderCount = orders.Count;
|
||||
|
||||
// 计算高度
|
||||
int visibleCount = Mathf.Min(orderCount, (int)MaxVisibleOrders);
|
||||
float contentHeight = TitleHeight + Spacing;
|
||||
contentHeight += Mathf.Max(1, visibleCount) * (BarHeight + Spacing);
|
||||
contentHeight += Padding;
|
||||
|
||||
float contentHeight = Padding * 2 + Text.LineHeight + Spacing; // 标题
|
||||
contentHeight += Mathf.Max(1, visibleCount) * (BarHeight + Spacing + 14f); // 订单(进度条+标签)
|
||||
float totalHeight = Mathf.Max(75f, contentHeight);
|
||||
|
||||
Rect gizmoRect = new Rect(topLeft.x, topLeft.y - (totalHeight - 75f), GetWidth(maxWidth), totalHeight);
|
||||
Widgets.DrawWindowBackground(gizmoRect);
|
||||
Rect rect = new Rect(topLeft.x, topLeft.y - (totalHeight - 75f), GetWidth(maxWidth), totalHeight);
|
||||
Widgets.DrawWindowBackground(rect);
|
||||
|
||||
float curY = gizmoRect.y + Padding;
|
||||
Rect innerRect = rect.ContractedBy(Padding);
|
||||
float curY = innerRect.y;
|
||||
|
||||
// 标题
|
||||
Rect titleRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, TitleHeight);
|
||||
// === 标题区域(可点击打开菜单) ===
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
|
||||
string title = $"孵化进度 ({orderCount}/{comp.Props.productionQueueLimit})";
|
||||
Widgets.Label(titleRect, title);
|
||||
|
||||
curY += TitleHeight + Spacing;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
Rect listRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, visibleCount * (BarHeight + Spacing));
|
||||
|
||||
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, Text.LineHeight);
|
||||
|
||||
string title;
|
||||
bool canAdd = orderCount < comp.Props.productionQueueLimit;
|
||||
|
||||
if (orderCount > 0)
|
||||
{
|
||||
if (orderCount > MaxVisibleOrders)
|
||||
// 显示第一个订单名称
|
||||
title = orders[0].label;
|
||||
if (orderCount > 1) title += $" (+{orderCount - 1})";
|
||||
}
|
||||
else
|
||||
{
|
||||
title = "选择孵化目标...";
|
||||
}
|
||||
|
||||
// 标题按钮
|
||||
if (canAdd)
|
||||
{
|
||||
if (Mouse.IsOver(titleRect))
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing);
|
||||
if (Mouse.IsOver(listRect))
|
||||
{
|
||||
scrollPosition -= Event.current.delta.y * 0.5f;
|
||||
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
|
||||
}
|
||||
Widgets.DrawHighlight(titleRect);
|
||||
}
|
||||
|
||||
if (Widgets.ButtonInvisible(titleRect))
|
||||
{
|
||||
comp.ShowOrderMenuPublic();
|
||||
}
|
||||
|
||||
// 带下拉箭头的标题
|
||||
GUI.color = new Color(0.7f, 0.9f, 1f);
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width - 20f) + " ▼");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = new Color(0.5f, 0.5f, 0.5f);
|
||||
Widgets.Label(titleRect, title.Truncate(titleRect.width) + " (满)");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
curY += Text.LineHeight + Spacing;
|
||||
|
||||
// === 订单列表 ===
|
||||
if (orderCount > 0)
|
||||
{
|
||||
float listHeight = Mathf.Min(visibleCount, orderCount) * (BarHeight + Spacing + 14f);
|
||||
Rect listRect = new Rect(innerRect.x, curY, innerRect.width, listHeight);
|
||||
|
||||
// 滚动支持
|
||||
if (orderCount > MaxVisibleOrders && Mouse.IsOver(listRect))
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing + 14f);
|
||||
scrollPosition -= Event.current.delta.y * 0.5f;
|
||||
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
|
||||
}
|
||||
|
||||
GUI.BeginClip(listRect);
|
||||
@@ -77,97 +114,98 @@ namespace ArachnaeSwarm
|
||||
for (int i = 0; i < orderCount; i++)
|
||||
{
|
||||
var order = orders[i];
|
||||
Rect barRect = new Rect(0, drawY, listRect.width, BarHeight);
|
||||
float itemHeight = BarHeight + 14f;
|
||||
Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight);
|
||||
|
||||
if (barRect.yMax > 0 && barRect.y < listRect.height)
|
||||
if (itemRect.yMax > 0 && itemRect.y < listRect.height)
|
||||
{
|
||||
DrawOrderBar(barRect, order, i);
|
||||
DrawOrderItem(itemRect, order, i);
|
||||
}
|
||||
drawY += BarHeight + Spacing;
|
||||
drawY += itemHeight + Spacing;
|
||||
}
|
||||
|
||||
GUI.EndClip();
|
||||
|
||||
if (orderCount > MaxVisibleOrders)
|
||||
{
|
||||
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing);
|
||||
float scrollBarHeight = listRect.height * (MaxVisibleOrders / (float)orderCount);
|
||||
float scrollBarY = curY + (scrollPosition / scrollMax) * (listRect.height - scrollBarHeight);
|
||||
|
||||
Rect scrollBarRect = new Rect(gizmoRect.xMax - 6f, scrollBarY, 4f, scrollBarHeight);
|
||||
Widgets.DrawBoxSolid(scrollBarRect, new Color(1f, 1f, 1f, 0.3f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect emptyRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, BarHeight);
|
||||
// 无订单时的提示
|
||||
Text.Font = GameFont.Tiny;
|
||||
GUI.color = Color.gray;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(emptyRect, "无订单 - 点击添加");
|
||||
GUI.color = new Color(0.7f, 0.7f, 0.7f);
|
||||
Widgets.Label(new Rect(innerRect.x, curY, innerRect.width, 20f), "就绪 - 点击上方选择目标");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
return new GizmoResult(GizmoState.Clear);
|
||||
}
|
||||
|
||||
private void DrawOrderBar(Rect rect, PawnOrderDisplayInfo order, int index)
|
||||
private void DrawOrderItem(Rect rect, PawnOrderDisplayInfo order, int index)
|
||||
{
|
||||
Widgets.DrawBoxSolid(rect, new Color(0.08f, 0.08f, 0.1f, 0.9f));
|
||||
|
||||
float labelHeight = 14f;
|
||||
|
||||
// 标签行
|
||||
Text.Font = GameFont.Tiny;
|
||||
Rect labelRect = new Rect(rect.x, rect.y, rect.width - 20f, labelHeight);
|
||||
|
||||
if (order.status == OrderStatus.WaitingForLarva)
|
||||
{
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleLeft;
|
||||
Rect labelRect = new Rect(rect.x + 4f, rect.y, rect.width - 28f, rect.height);
|
||||
GUI.color = new Color(1f, 0.8f, 0.4f);
|
||||
Widgets.Label(labelRect, $"🐛 {order.label} [等待幼虫]");
|
||||
GUI.color = Color.white;
|
||||
Widgets.Label(labelRect, $"{order.label} [等待幼虫]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 双向进度条
|
||||
float midX = rect.x + rect.width / 2f;
|
||||
float halfWidth = (rect.width - 28f) / 2f;
|
||||
|
||||
// 品质进度(向左生长,青色)
|
||||
float qualityWidth = halfWidth * order.qualityProgress;
|
||||
Rect qualityRect = new Rect(midX - qualityWidth, rect.y + 2f, qualityWidth, rect.height - 4f);
|
||||
Color qualityColor = Color.Lerp(new Color(0.2f, 0.5f, 0.6f), new Color(0.3f, 0.8f, 0.9f), order.qualityProgress);
|
||||
Widgets.DrawBoxSolid(qualityRect, qualityColor);
|
||||
|
||||
// 生产进度(向右生长,绿色)
|
||||
float progressWidth = halfWidth * order.progress;
|
||||
Rect progressRect = new Rect(midX, rect.y + 2f, progressWidth, rect.height - 4f);
|
||||
Color progressColor = Color.Lerp(new Color(0.3f, 0.5f, 0.3f), new Color(0.4f, 0.9f, 0.4f), order.progress);
|
||||
Widgets.DrawBoxSolid(progressRect, progressColor);
|
||||
|
||||
// 中线
|
||||
Widgets.DrawLineVertical(midX, rect.y + 2f, rect.height - 4f);
|
||||
|
||||
// 标签
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Rect labelRect = new Rect(rect.x, rect.y, rect.width - 24f, rect.height);
|
||||
GUI.color = Color.white;
|
||||
Widgets.Label(labelRect, $"{order.label} {order.progress.ToStringPercent("F0")}");
|
||||
|
||||
// 品质提示
|
||||
string tooltip = $"{order.label}\n生产进度: {order.progress.ToStringPercent()}\n品质进度: {order.qualityProgress.ToStringPercent()}\n预计品质: {order.estimatedQuality}\n剩余时间: {order.remainingTime}";
|
||||
TooltipHandler.TipRegion(rect, tooltip);
|
||||
Widgets.Label(labelRect, $"{order.label} {order.progress.ToStringPercent("F0")}");
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
|
||||
Rect cancelRect = new Rect(rect.xMax - 20f, rect.y + 2f, 18f, rect.height - 4f);
|
||||
if (Widgets.ButtonText(cancelRect, "X", false))
|
||||
// 取消按钮
|
||||
Rect cancelRect = new Rect(rect.xMax - 16f, rect.y, 16f, labelHeight);
|
||||
if (Widgets.ButtonText(cancelRect, "×", false))
|
||||
{
|
||||
comp.RemoveOrderByIndex(index);
|
||||
}
|
||||
|
||||
Widgets.DrawBox(rect);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
// 进度条
|
||||
Rect barRect = new Rect(rect.x, rect.y + labelHeight, rect.width, BarHeight);
|
||||
|
||||
if (order.status == OrderStatus.Incubating)
|
||||
{
|
||||
// 双向进度条:品质向左,进度向右
|
||||
float midX = barRect.x + barRect.width / 2f;
|
||||
float halfWidth = barRect.width / 2f;
|
||||
|
||||
// 背景
|
||||
GUI.DrawTexture(barRect, EmptyBarTex);
|
||||
|
||||
// 品质进度(向左)
|
||||
float qualityWidth = halfWidth * order.qualityProgress;
|
||||
Rect qualityRect = new Rect(midX - qualityWidth, barRect.y, qualityWidth, barRect.height);
|
||||
GUI.DrawTexture(qualityRect, QualityBarTex);
|
||||
|
||||
// 生产进度(向右)
|
||||
float progressWidth = halfWidth * order.progress;
|
||||
Rect progressRect = new Rect(midX, barRect.y, progressWidth, barRect.height);
|
||||
GUI.DrawTexture(progressRect, ProgressBarTex);
|
||||
|
||||
// 中线
|
||||
Widgets.DrawLineVertical(midX, barRect.y, barRect.height);
|
||||
|
||||
// Tooltip
|
||||
string tooltip = $"{order.label}\n品质: {order.qualityProgress.ToStringPercent()} → {order.estimatedQuality}\n进度: {order.progress.ToStringPercent()}\n剩余: {order.remainingTime}";
|
||||
TooltipHandler.TipRegion(barRect, tooltip);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 等待幼虫状态:显示等待指示
|
||||
GUI.DrawTexture(barRect, EmptyBarTex);
|
||||
Text.Font = GameFont.Tiny;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.8f, 0.6f, 0.2f);
|
||||
Widgets.Label(barRect, "等待幼虫激活");
|
||||
GUI.color = Color.white;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
275
Source/ArachnaeSwarm/Buildings/IncubatorUtils.cs
Normal file
275
Source/ArachnaeSwarm/Buildings/IncubatorUtils.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 孵化器通用工具类
|
||||
/// 统一核心算法,保持各孵化器行为一致
|
||||
/// </summary>
|
||||
public static class IncubatorUtils
|
||||
{
|
||||
// ============================================
|
||||
// 通量系统
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 计算通量效率(0-1之间,通量越高效率越高)
|
||||
/// </summary>
|
||||
public static float GetFluxEfficiency(float neutronFlux)
|
||||
{
|
||||
// 与 IFluxControllerExtensions.GetEfficiency 保持一致
|
||||
return Mathf.Pow(neutronFlux, 0.7f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否处于休眠状态
|
||||
/// </summary>
|
||||
public static bool IsDormant(float neutronFlux)
|
||||
{
|
||||
return neutronFlux < 0.05f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模式名称
|
||||
/// </summary>
|
||||
public static string GetFluxModeName(FluxMode mode)
|
||||
{
|
||||
return mode switch
|
||||
{
|
||||
FluxMode.Manual => "手动",
|
||||
FluxMode.Quality => "品质",
|
||||
FluxMode.Balance => "平衡",
|
||||
FluxMode.Speed => "速度",
|
||||
_ => "?"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模式简称
|
||||
/// </summary>
|
||||
public static string GetFluxModeShort(FluxMode mode)
|
||||
{
|
||||
return mode switch
|
||||
{
|
||||
FluxMode.Manual => "M",
|
||||
FluxMode.Quality => "Q",
|
||||
FluxMode.Balance => "B",
|
||||
FluxMode.Speed => "S",
|
||||
_ => "?"
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 品质系统
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 计算品质增长(低通量时增长更快)
|
||||
/// 公式:qualityGain = speedFactor * (1 + (1 - flux) * 0.5)
|
||||
/// </summary>
|
||||
public static float CalculateQualityGain(float neutronFlux, float speedFactor)
|
||||
{
|
||||
float qualityBonus = 1f + (1f - neutronFlux) * 0.5f;
|
||||
return speedFactor * qualityBonus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算休眠时品质衰减(10%/天)
|
||||
/// </summary>
|
||||
public static float CalculateQualityDecay(float qualityTotal)
|
||||
{
|
||||
return (qualityTotal * 0.1f) / 60000f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据品质百分比获取品质等级
|
||||
/// </summary>
|
||||
public static QualityCategory GetQualityFromPercent(float qualityPercent, List<QualityThreshold> thresholds)
|
||||
{
|
||||
if (thresholds.NullOrEmpty()) return QualityCategory.Normal;
|
||||
|
||||
foreach (var threshold in thresholds.OrderByDescending(q => q.threshold))
|
||||
{
|
||||
if (qualityPercent >= threshold.threshold)
|
||||
return threshold.quality;
|
||||
}
|
||||
|
||||
return thresholds.OrderBy(q => q.threshold).First().quality;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认品质阈值
|
||||
/// </summary>
|
||||
public static List<QualityThreshold> GetDefaultQualityThresholds()
|
||||
{
|
||||
return new List<QualityThreshold>
|
||||
{
|
||||
new QualityThreshold { quality = QualityCategory.Legendary, threshold = 0.99f },
|
||||
new QualityThreshold { quality = QualityCategory.Masterwork, threshold = 0.90f },
|
||||
new QualityThreshold { quality = QualityCategory.Excellent, threshold = 0.70f },
|
||||
new QualityThreshold { quality = QualityCategory.Good, threshold = 0.50f },
|
||||
new QualityThreshold { quality = QualityCategory.Normal, threshold = 0.20f },
|
||||
new QualityThreshold { quality = QualityCategory.Poor, threshold = 0.10f },
|
||||
new QualityThreshold { quality = QualityCategory.Awful, threshold = 0f }
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 幼虫系统
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 搜索可用幼虫
|
||||
/// </summary>
|
||||
public static Pawn FindLarva(Map map, IntVec3 position, Faction faction, float searchRadius = 50f)
|
||||
{
|
||||
if (map == null) return null;
|
||||
|
||||
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
|
||||
{
|
||||
if (pawn.def.defName == "ArachnaeBase_Race_Larva" &&
|
||||
!pawn.Downed && !pawn.Dead &&
|
||||
pawn.Faction == faction &&
|
||||
position.DistanceTo(pawn.Position) <= searchRadius)
|
||||
{
|
||||
return pawn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索多个可用幼虫
|
||||
/// </summary>
|
||||
public static List<Pawn> FindLarvae(Map map, IntVec3 position, Faction faction, int maxCount, float searchRadius = 50f, List<Pawn> exclude = null)
|
||||
{
|
||||
var result = new List<Pawn>();
|
||||
if (map == null) return result;
|
||||
|
||||
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
|
||||
{
|
||||
if (result.Count >= maxCount) break;
|
||||
if (pawn.def.defName == "ArachnaeBase_Race_Larva" &&
|
||||
!pawn.Downed && !pawn.Dead &&
|
||||
pawn.Faction == faction &&
|
||||
(exclude == null || !exclude.Contains(pawn)) &&
|
||||
position.DistanceTo(pawn.Position) <= searchRadius)
|
||||
{
|
||||
result.Add(pawn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 自动通量计算
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 计算自动通量目标值
|
||||
/// </summary>
|
||||
/// <param name="mode">通量模式</param>
|
||||
/// <param name="qualityPercent">当前品质百分比</param>
|
||||
/// <param name="progressPercent">当前进度百分比</param>
|
||||
/// <param name="currentFuel">当前燃料量</param>
|
||||
/// <returns>目标通量值</returns>
|
||||
public static float CalculateAutoFlux(FluxMode mode, float qualityPercent, float progressPercent, float currentFuel)
|
||||
{
|
||||
if (mode == FluxMode.Manual) return -1f; // 手动模式不计算
|
||||
|
||||
float gap = qualityPercent - progressPercent;
|
||||
float targetFlux;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case FluxMode.Quality:
|
||||
// 品质优先:保持品质领先
|
||||
if (qualityPercent >= 0.98f) targetFlux = 1.0f;
|
||||
else if (gap > 0.2f) targetFlux = 0.6f;
|
||||
else if (gap > 0.1f) targetFlux = 0.45f;
|
||||
else if (gap > 0f) targetFlux = 0.35f;
|
||||
else targetFlux = 0.2f;
|
||||
break;
|
||||
|
||||
case FluxMode.Speed:
|
||||
// 速度优先:尽快完成,必要时降速保品质
|
||||
if (qualityPercent >= 0.95f) targetFlux = 1.0f;
|
||||
else if (qualityPercent < 0.3f && progressPercent > 0.5f) targetFlux = 0.7f;
|
||||
else if (qualityPercent < 0.2f && progressPercent > 0.7f) targetFlux = 0.5f;
|
||||
else targetFlux = 1.0f;
|
||||
break;
|
||||
|
||||
case FluxMode.Balance:
|
||||
default:
|
||||
// 平衡模式:动态调节
|
||||
if (qualityPercent >= 0.95f) targetFlux = 1.0f;
|
||||
else if (gap > 0.15f) targetFlux = 0.8f;
|
||||
else if (gap > 0.05f) targetFlux = 0.6f;
|
||||
else if (gap > -0.05f) targetFlux = 0.5f;
|
||||
else if (gap > -0.15f) targetFlux = 0.35f;
|
||||
else targetFlux = 0.2f;
|
||||
break;
|
||||
}
|
||||
|
||||
// 燃料保护
|
||||
if (currentFuel < 20f)
|
||||
targetFlux = Mathf.Min(targetFlux, 0.3f);
|
||||
else if (currentFuel < 50f)
|
||||
targetFlux = Mathf.Min(targetFlux, 0.5f);
|
||||
|
||||
return targetFlux;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 平滑调节通量(用于自动模式)
|
||||
/// </summary>
|
||||
public static float SmoothFlux(float currentFlux, float targetFlux, float lerpSpeed = 0.05f)
|
||||
{
|
||||
return Mathf.Lerp(currentFlux, targetFlux, lerpSpeed);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 燃料消耗
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 计算每tick燃料消耗
|
||||
/// </summary>
|
||||
/// <param name="baseFuelPerDay">每天基础消耗</param>
|
||||
/// <param name="fluxEfficiency">通量效率</param>
|
||||
/// <param name="orderCount">正在处理的订单数</param>
|
||||
public static float CalculateFuelConsumption(float baseFuelPerDay, float fluxEfficiency, int orderCount = 1)
|
||||
{
|
||||
return (baseFuelPerDay * fluxEfficiency * orderCount) / 60000f;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 速度计算
|
||||
// ============================================
|
||||
|
||||
/// <summary>
|
||||
/// 计算实际进度速度
|
||||
/// </summary>
|
||||
public static float CalculateProgressSpeed(float fluxEfficiency, float speedFactor, float baseMultiplier = 5f)
|
||||
{
|
||||
return speedFactor * fluxEfficiency * baseMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算需要减少的ticks(带随机)
|
||||
/// </summary>
|
||||
public static int CalculateExtraTicks(float progressSpeed)
|
||||
{
|
||||
float extra = progressSpeed - 1f;
|
||||
if (extra <= 0) return 0;
|
||||
|
||||
int extraTicks = Mathf.FloorToInt(extra);
|
||||
if (Rand.Value < (extra - extraTicks)) extraTicks++;
|
||||
return extraTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user