暂存
This commit is contained in:
@@ -85,7 +85,11 @@
|
||||
<Compile Include="CompProperties_AbilityBindDrone.cs" />
|
||||
<Compile Include="JobGiver_MaintainBuildings.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Compile Include="WULA_AutoMechCarrier\CompAutoMechCarrier.cs" />
|
||||
<Compile Include="WULA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
|
||||
<Compile Include="WULA_AutoMechCarrier\PawnProductionEntry.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||
|
||||
195
Source/ArachnaeSwarm/WULA_AutoMechCarrier/CompAutoMechCarrier.cs
Normal file
195
Source/ArachnaeSwarm/WULA_AutoMechCarrier/CompAutoMechCarrier.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI.Group;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompAutoMechCarrier : CompMechCarrier
|
||||
{
|
||||
#region Reflected Fields
|
||||
private static FieldInfo spawnedPawnsField;
|
||||
private static FieldInfo cooldownTicksRemainingField;
|
||||
private static FieldInfo innerContainerField;
|
||||
|
||||
private List<Pawn> SpawnedPawns
|
||||
{
|
||||
get
|
||||
{
|
||||
if (spawnedPawnsField == null)
|
||||
spawnedPawnsField = typeof(CompMechCarrier).GetField("spawnedPawns", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return (List<Pawn>)spawnedPawnsField.GetValue(this);
|
||||
}
|
||||
}
|
||||
|
||||
private int CooldownTicksRemaining
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cooldownTicksRemainingField == null)
|
||||
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return (int)cooldownTicksRemainingField.GetValue(this);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (cooldownTicksRemainingField == null)
|
||||
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
cooldownTicksRemainingField.SetValue(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ThingOwner InnerContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (innerContainerField == null)
|
||||
innerContainerField = typeof(CompMechCarrier).GetField("innerContainer", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return (ThingOwner)innerContainerField.GetValue(this);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public CompProperties_AutoMechCarrier AutoProps => (CompProperties_AutoMechCarrier)props;
|
||||
|
||||
private int TotalPawnCapacity => AutoProps.productionQueue.Sum(e => e.count);
|
||||
|
||||
private int LiveSpawnedPawnsCount(PawnKindDef kind)
|
||||
{
|
||||
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
|
||||
return SpawnedPawns.Count(p => p.kindDef == kind);
|
||||
}
|
||||
|
||||
private AcceptanceReport CanSpawnNow(PawnKindDef kind)
|
||||
{
|
||||
if (parent is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Downed || pawn.Dead || !pawn.Spawned))
|
||||
return false;
|
||||
if (CooldownTicksRemaining > 0)
|
||||
return "CooldownTime".Translate() + " " + CooldownTicksRemaining.ToStringSecondsFromTicks();
|
||||
|
||||
PawnProductionEntry entry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
|
||||
int cost = entry.cost ?? Props.costPerPawn;
|
||||
|
||||
if (!AutoProps.freeProduction && InnerContainer.TotalStackCountOfDef(Props.fixedIngredient) < cost)
|
||||
return "MechCarrierNotEnoughResources".Translate();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void TrySpawnPawn(PawnKindDef kind)
|
||||
{
|
||||
PawnGenerationRequest request = new PawnGenerationRequest(kind, parent.Faction, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: true);
|
||||
Pawn pawn = PawnGenerator.GeneratePawn(request);
|
||||
GenSpawn.Spawn(pawn, parent.Position, parent.Map);
|
||||
SpawnedPawns.Add(pawn);
|
||||
|
||||
if (parent is Pawn p && p.GetLord() != null)
|
||||
p.GetLord().AddPawn(pawn);
|
||||
|
||||
if (!AutoProps.freeProduction)
|
||||
{
|
||||
PawnProductionEntry entry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
|
||||
int costLeft = entry.cost ?? Props.costPerPawn;
|
||||
|
||||
List<Thing> things = new List<Thing>(InnerContainer);
|
||||
for (int j = 0; j < things.Count; j++)
|
||||
{
|
||||
Thing thing = InnerContainer.Take(things[j], Mathf.Min(things[j].stackCount, costLeft));
|
||||
costLeft -= thing.stackCount;
|
||||
thing.Destroy();
|
||||
if (costLeft <= 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
PawnProductionEntry spawnEntry = AutoProps.productionQueue.First(e => e.pawnKind == kind);
|
||||
CooldownTicksRemaining = spawnEntry.cooldownTicks ?? Props.cooldownTicks;
|
||||
|
||||
if (Props.spawnedMechEffecter != null)
|
||||
EffecterTrigger(Props.spawnedMechEffecter, Props.attachSpawnedMechEffecter, pawn);
|
||||
if (Props.spawnEffecter != null)
|
||||
EffecterTrigger(Props.spawnEffecter, Props.attachSpawnedEffecter, parent);
|
||||
}
|
||||
|
||||
private void EffecterTrigger(EffecterDef effecterDef, bool attach, Thing target)
|
||||
{
|
||||
Effecter effecter = new Effecter(effecterDef);
|
||||
effecter.Trigger(attach ? ((TargetInfo)target) : new TargetInfo(target.Position, target.Map), TargetInfo.Invalid);
|
||||
effecter.Cleanup();
|
||||
}
|
||||
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
|
||||
if (parent.IsHashIntervalTick(60)) // 每秒检查一次
|
||||
{
|
||||
// 检查是否有抑制生产的Hediff
|
||||
if (AutoProps.disableHediff != null && (parent as Pawn)?.health.hediffSet.HasHediff(AutoProps.disableHediff) == true)
|
||||
{
|
||||
return; // 有Hediff,停止生产
|
||||
}
|
||||
|
||||
// 1. 先检查是否满员
|
||||
bool isFull = true;
|
||||
foreach (var entry in AutoProps.productionQueue)
|
||||
{
|
||||
if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
|
||||
{
|
||||
isFull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFull)
|
||||
{
|
||||
return; // 如果已满员,则不进行任何操作,包括冷却计时
|
||||
}
|
||||
|
||||
// 2. 如果未满员,才检查冷却时间
|
||||
if (CooldownTicksRemaining > 0) return;
|
||||
|
||||
// 3. 寻找空位并生产
|
||||
foreach (var entry in AutoProps.productionQueue)
|
||||
{
|
||||
if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
|
||||
{
|
||||
if (CanSpawnNow(entry.pawnKind).Accepted)
|
||||
{
|
||||
TrySpawnPawn(entry.pawnKind);
|
||||
break; // 每次只生产一个
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
// 移除所有Gizmo逻辑
|
||||
return Enumerable.Empty<Gizmo>();
|
||||
}
|
||||
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
|
||||
string text = "Pawns: " + SpawnedPawns.Count + " / " + TotalPawnCapacity;
|
||||
|
||||
foreach (var entry in AutoProps.productionQueue)
|
||||
{
|
||||
text += $"\n- {entry.pawnKind.LabelCap}: {LiveSpawnedPawnsCount(entry.pawnKind)} / {entry.count}";
|
||||
}
|
||||
|
||||
if (CooldownTicksRemaining > 0)
|
||||
{
|
||||
text += "\n" + "CooldownTime".Translate() + ": " + CooldownTicksRemaining.ToStringSecondsFromTicks();
|
||||
}
|
||||
|
||||
if (!AutoProps.freeProduction)
|
||||
{
|
||||
text += "\n" + base.CompInspectStringExtra();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_AutoMechCarrier : CompProperties_MechCarrier
|
||||
{
|
||||
// XML中定义,生产是否消耗资源
|
||||
public bool freeProduction = false;
|
||||
|
||||
// 如果单位拥有这个Hediff,则停止生产
|
||||
public HediffDef disableHediff;
|
||||
|
||||
// 定义生产队列
|
||||
public List<PawnProductionEntry> productionQueue = new List<PawnProductionEntry>();
|
||||
|
||||
public CompProperties_AutoMechCarrier()
|
||||
{
|
||||
// 确保这个属性类指向我们新的功能实现类
|
||||
compClass = typeof(CompAutoMechCarrier);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(ThingDef parentDef)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parentDef))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (productionQueue.NullOrEmpty())
|
||||
{
|
||||
yield return "CompProperties_AutoMechCarrier must have at least one entry in productionQueue.";
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResolveReferences(ThingDef parentDef)
|
||||
{
|
||||
base.ResolveReferences(parentDef);
|
||||
// Prevent division by zero if costPerPawn is not set, which the base game AI might try to access.
|
||||
if (costPerPawn <= 0)
|
||||
{
|
||||
costPerPawn = 1;
|
||||
}
|
||||
|
||||
// 如果spawnPawnKind为空(因为我们用了新的队列系统),
|
||||
// 就从队列里取第一个作为“假”值,以防止基类方法在生成Gizmo标签时出错。
|
||||
if (spawnPawnKind == null && !productionQueue.NullOrEmpty())
|
||||
{
|
||||
spawnPawnKind = productionQueue[0].pawnKind;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
/// <summary>
|
||||
/// A data class to hold information about a pawn to be produced in a queue.
|
||||
/// Used in XML definitions.
|
||||
/// </summary>
|
||||
public class PawnProductionEntry
|
||||
{
|
||||
// The PawnKindDef of the unit to spawn.
|
||||
public PawnKindDef pawnKind;
|
||||
|
||||
// The maximum number of this kind of unit to maintain.
|
||||
public int count = 1;
|
||||
|
||||
// Optional: specific cooldown for this entry. If not set, the parent comp's cooldown is used.
|
||||
public int? cooldownTicks;
|
||||
|
||||
// Optional: specific cost for this entry. If not set, the parent comp's costPerPawn is used.
|
||||
public int? cost;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user