203 lines
8.0 KiB
C#
203 lines
8.0 KiB
C#
using RimWorld;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Verse;
|
|
using Verse.AI;
|
|
using UnityEngine;
|
|
|
|
namespace ArachnaeSwarm
|
|
{
|
|
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>();
|
|
public QueuedPawnSpawnEntry selectedEntry;
|
|
|
|
private CompRefuelableNutrition _fuelComp;
|
|
private CompAffectedByFacilities _facilitiesComp;
|
|
|
|
public CompProperties_QueuedPawnSpawner Props => (CompProperties_QueuedPawnSpawner)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 entry in Props.spawnablePawns)
|
|
{
|
|
if (entry.requiredResearch != null && !entry.requiredResearch.IsFinished)
|
|
{
|
|
yield return new FloatMenuOption("ARA_Incubate".Translate(entry.pawnKind.label) + " (" + "Requires".Translate() + ": " + entry.requiredResearch.label + ")", null);
|
|
}
|
|
else
|
|
{
|
|
yield return new FloatMenuOption("ARA_Incubate".Translate(entry.pawnKind.label), () =>
|
|
{
|
|
this.selectedEntry = entry;
|
|
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_AddToQueueJob"), parent);
|
|
selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddToQueue()
|
|
{
|
|
if (selectedEntry == null)
|
|
{
|
|
Log.Error("Tried to add to queue but selectedEntry was null.");
|
|
return;
|
|
}
|
|
productionOrders.Add(new QueuedProductionOrder { entry = selectedEntry });
|
|
selectedEntry = null;
|
|
}
|
|
|
|
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)
|
|
{
|
|
var 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();
|
|
|
|
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]);
|
|
Scribe_Deep.Look(ref selectedEntry, "selectedEntry");
|
|
}
|
|
|
|
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.entry.pawnKind.LabelCap,
|
|
defaultDesc = "CommandCancelProductionDesc".Translate(),
|
|
icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel"),
|
|
action = () =>
|
|
{
|
|
productionOrders.Remove(lastOrder);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
} |