暂存
This commit is contained in:
@@ -105,6 +105,10 @@
|
||||
<Compile Include="WULA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
|
||||
<Compile Include="WULA_AutoMechCarrier\PawnProductionEntry.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CompInteractiveProducer.cs" />
|
||||
<Compile Include="JobDriver_StartProduction.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace ArachnaeSwarm
|
||||
public float totalNutritionNeeded;
|
||||
}
|
||||
|
||||
// We do NOT inherit from CompProperties_Refuelable anymore
|
||||
public class CompProperties_InteractiveProducer : CompProperties
|
||||
{
|
||||
public List<ProcessDef> processes;
|
||||
@@ -35,12 +34,10 @@ namespace ArachnaeSwarm
|
||||
public float maxSafeTemperature = 32f;
|
||||
public float penaltyPerDegreePerTick = 0.00001f;
|
||||
|
||||
// Manually added properties from CompProperties_Refuelable
|
||||
public float fuelCapacity = 100f;
|
||||
public bool targetFuelLevelConfigurable = true;
|
||||
public bool showAllowAutoRefuelToggle = true;
|
||||
public string fuelLabel = "Nutrition";
|
||||
public Texture2D fuelIcon = null; // Let it default or specify
|
||||
|
||||
public CompProperties_InteractiveProducer()
|
||||
{
|
||||
@@ -61,11 +58,10 @@ namespace ArachnaeSwarm
|
||||
private int ticksUnderOptimalConditions;
|
||||
private float temperaturePenaltyPercent;
|
||||
|
||||
// --- Manually added state from CompRefuelable ---
|
||||
private float configuredTargetFuelLevel = -1f;
|
||||
public bool allowAutoRefuel = true;
|
||||
|
||||
// --- Manually added static resources from CompRefuelable ---
|
||||
// --- Static Resources ---
|
||||
private static readonly Texture2D SetTargetFuelLevelCommand = ContentFinder<Texture2D>.Get("UI/Commands/SetTargetFuelLevel");
|
||||
private static readonly Vector2 FuelBarSize = new Vector2(1f, 0.2f);
|
||||
private static readonly Material FuelBarFilledMat = SolidColorMaterials.SimpleSolidColorMaterial(new Color(0.6f, 0.56f, 0.13f));
|
||||
@@ -79,7 +75,6 @@ namespace ArachnaeSwarm
|
||||
public bool StorageTabVisible => true;
|
||||
public float NutritionStored => containedNutrition + GetNutritionInContainer();
|
||||
|
||||
// --- Manually added properties from CompRefuelable ---
|
||||
public float TargetFuelLevel
|
||||
{
|
||||
get => configuredTargetFuelLevel < 0f ? Props.fuelCapacity : configuredTargetFuelLevel;
|
||||
@@ -91,16 +86,19 @@ namespace ArachnaeSwarm
|
||||
// --- Initialization & Scribe ---
|
||||
public CompInteractiveProducer() { innerContainer = new ThingOwner<Thing>(this, false, LookMode.Deep); }
|
||||
|
||||
public override void PostMake()
|
||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||
{
|
||||
base.PostMake();
|
||||
allowedNutritionSettings = new StorageSettings(this);
|
||||
if (parent.def.building.defaultStorageSettings != null)
|
||||
base.PostSpawnSetup(respawningAfterLoad);
|
||||
if (!respawningAfterLoad)
|
||||
{
|
||||
allowedNutritionSettings.CopyFrom(parent.def.building.defaultStorageSettings);
|
||||
allowedNutritionSettings = new StorageSettings(this);
|
||||
if (parent.def.building.defaultStorageSettings != null)
|
||||
{
|
||||
allowedNutritionSettings.CopyFrom(parent.def.building.defaultStorageSettings);
|
||||
}
|
||||
UpdateFuelFilter();
|
||||
TargetFuelLevel = Props.fuelCapacity;
|
||||
}
|
||||
UpdateFuelFilter();
|
||||
TargetFuelLevel = Props.fuelCapacity; // Initialize target level
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
@@ -139,9 +137,7 @@ namespace ArachnaeSwarm
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
innerContainer.ThingOwnerTick();
|
||||
|
||||
if (this.IsHashIntervalTick(60) && NutritionStored < TargetFuelLevel)
|
||||
if (parent.IsHashIntervalTick(60) && NutritionStored < TargetFuelLevel && allowAutoRefuel)
|
||||
{
|
||||
TryAbsorbNutritiousThing();
|
||||
}
|
||||
@@ -178,12 +174,120 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// ... (Production Flow methods remain the same) ...
|
||||
// --- Production Flow ---
|
||||
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
|
||||
{
|
||||
if (InProduction || !selPawn.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (Props.whitelist != null && !Props.whitelist.Contains(selPawn.kindDef))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var process in Props.processes)
|
||||
{
|
||||
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
|
||||
{
|
||||
// When the float menu is clicked, we set the selected process on the comp,
|
||||
// so the JobDriver knows which process to start.
|
||||
this._selectedProcess = process;
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_IncubateJob"), parent);
|
||||
selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// This is now called by the JobDriver, without arguments.
|
||||
public void StartProduction()
|
||||
{
|
||||
if (_selectedProcess == null)
|
||||
{
|
||||
Log.Error("CompInteractiveProducer tried to start production, but _selectedProcess is null.");
|
||||
return;
|
||||
}
|
||||
productionUntilTick = Find.TickManager.TicksGame + _selectedProcess.productionTicks;
|
||||
ticksUnderOptimalConditions = 0;
|
||||
temperaturePenaltyPercent = 0f;
|
||||
}
|
||||
|
||||
private void FinishProduction()
|
||||
{
|
||||
float baseQuality = (_selectedProcess.productionTicks > 0) ? (float)ticksUnderOptimalConditions / _selectedProcess.productionTicks : 0f;
|
||||
float finalQualityScore = Mathf.Clamp01(baseQuality - temperaturePenaltyPercent);
|
||||
|
||||
for (int i = 0; i < Props.spawnCount.RandomInRange; i++)
|
||||
{
|
||||
Thing thing = ThingMaker.MakeThing(_selectedProcess.thingDef);
|
||||
if (thing.TryGetComp<CompQuality>() is CompQuality compQuality)
|
||||
{
|
||||
if (finalQualityScore >= 0.99f) compQuality.SetQuality(QualityCategory.Legendary, ArtGenerationContext.Colony);
|
||||
else if (finalQualityScore >= 0.90f) compQuality.SetQuality(QualityCategory.Masterwork, ArtGenerationContext.Colony);
|
||||
else if (finalQualityScore >= 0.70f) compQuality.SetQuality(QualityCategory.Excellent, ArtGenerationContext.Colony);
|
||||
else if (finalQualityScore >= 0.50f) compQuality.SetQuality(QualityCategory.Good, ArtGenerationContext.Colony);
|
||||
else if (finalQualityScore >= 0.20f) compQuality.SetQuality(QualityCategory.Normal, ArtGenerationContext.Colony);
|
||||
else if (finalQualityScore >= 0.10f) compQuality.SetQuality(QualityCategory.Poor, ArtGenerationContext.Colony);
|
||||
else compQuality.SetQuality(QualityCategory.Awful, ArtGenerationContext.Colony);
|
||||
}
|
||||
GenPlace.TryPlaceThing(thing, parent.InteractionCell, parent.Map, ThingPlaceMode.Near);
|
||||
}
|
||||
|
||||
if (Props.destroyOnSpawn)
|
||||
{
|
||||
parent.Destroy();
|
||||
}
|
||||
ResetProduction();
|
||||
}
|
||||
|
||||
private void ResetProduction()
|
||||
{
|
||||
_selectedProcess = null;
|
||||
productionUntilTick = -1;
|
||||
}
|
||||
|
||||
// --- Fuel System ---
|
||||
private void UpdateFuelFilter() { /* ... */ }
|
||||
private void TryAbsorbNutritiousThing() { /* ... */ }
|
||||
public bool IsAcceptableFuel(ThingDef def) { /* ... */ }
|
||||
private void UpdateFuelFilter()
|
||||
{
|
||||
if (Props.fuelAcceptance != null)
|
||||
{
|
||||
var filter = allowedNutritionSettings.filter;
|
||||
filter.SetDisallowAll();
|
||||
if (!Props.fuelAcceptance.whitelist.NullOrEmpty())
|
||||
{
|
||||
foreach (var def in Props.fuelAcceptance.whitelist) filter.SetAllow(def, true);
|
||||
}
|
||||
if (!Props.fuelAcceptance.blacklist.NullOrEmpty())
|
||||
{
|
||||
foreach (var def in Props.fuelAcceptance.blacklist) filter.SetAllow(def, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryAbsorbNutritiousThing()
|
||||
{
|
||||
for (int i = innerContainer.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Thing thing = innerContainer[i];
|
||||
if (IsAcceptableFuel(thing.def))
|
||||
{
|
||||
float nutrition = thing.GetStatValue(StatDefOf.Nutrition);
|
||||
int numToAbsorb = Mathf.CeilToInt(Mathf.Min((float)thing.stackCount, 1f));
|
||||
containedNutrition += (float)numToAbsorb * nutrition;
|
||||
thing.SplitOff(numToAbsorb).Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAcceptableFuel(ThingDef def)
|
||||
{
|
||||
var acceptance = Props.fuelAcceptance;
|
||||
if (acceptance == null) return true;
|
||||
if (acceptance.blacklist != null && acceptance.blacklist.Contains(def)) return false;
|
||||
if (acceptance.whitelist != null && !acceptance.whitelist.NullOrEmpty()) return acceptance.whitelist.Contains(def);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- IStoreSettingsParent & IThingHolder ---
|
||||
public StorageSettings GetStoreSettings() => allowedNutritionSettings;
|
||||
@@ -218,19 +322,17 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Ported logic from CompRefuelable
|
||||
sb.Append(Props.fuelLabel + ": " + NutritionStored.ToString("F0") + " / " + Props.fuelCapacity.ToString("F0"));
|
||||
if (InProduction)
|
||||
{
|
||||
float ticksRemaining = _selectedProcess.productionTicks * (NutritionStored / _selectedProcess.totalNutritionNeeded);
|
||||
sb.Append(" (" + ((int)ticksRemaining).ToStringTicksToPeriod() + ")");
|
||||
float nutritionRatePerDay = (_selectedProcess.totalNutritionNeeded / _selectedProcess.productionTicks) * 60000;
|
||||
sb.Append(" (-" + nutritionRatePerDay.ToString("F1") + "/day)");
|
||||
}
|
||||
if (Props.targetFuelLevelConfigurable)
|
||||
{
|
||||
sb.Append("\n" + "ConfiguredTargetFuelLevel".Translate(TargetFuelLevel.ToString("F0")));
|
||||
}
|
||||
|
||||
// Our production info
|
||||
if (InProduction)
|
||||
{
|
||||
sb.AppendLine();
|
||||
@@ -251,18 +353,16 @@ namespace ArachnaeSwarm
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> GetGizmos()
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
foreach (var g in base.GetGizmos()) yield return g;
|
||||
foreach (var g in base.CompGetGizmosExtra()) yield return g;
|
||||
|
||||
// Ported Gizmos from CompRefuelable
|
||||
if (Props.targetFuelLevelConfigurable)
|
||||
{
|
||||
var setTargetGizmo = new Command_SetTargetFuelLevel();
|
||||
setTargetGizmo.defaultLabel = "CommandSetTargetFuelLevel".Translate();
|
||||
setTargetGizmo.defaultDesc = "CommandSetTargetFuelLevelDesc".Translate();
|
||||
setTargetGizmo.icon = SetTargetFuelLevelCommand;
|
||||
// We need to create a simple wrapper to make it work
|
||||
setTargetGizmo.setter = (level) => this.TargetFuelLevel = level;
|
||||
setTargetGizmo.getter = () => this.TargetFuelLevel;
|
||||
setTargetGizmo.max = this.Props.fuelCapacity;
|
||||
@@ -292,6 +392,46 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// ... (The rest of the methods: FinishProduction, ResetProduction, GetNutritionInContainer etc.) ...
|
||||
private float GetNutritionInContainer()
|
||||
{
|
||||
float total = 0f;
|
||||
for (int i = 0; i < innerContainer.Count; i++)
|
||||
{
|
||||
total += (float)innerContainer[i].stackCount * innerContainer[i].GetStatValue(StatDefOf.Nutrition);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper for the Gizmo since we are not CompRefuelable
|
||||
public class Command_SetTargetFuelLevel : Command
|
||||
{
|
||||
public System.Action<float> setter;
|
||||
public System.Func<float> getter;
|
||||
public float max;
|
||||
|
||||
public override void ProcessInput(Event ev)
|
||||
{
|
||||
base.ProcessInput(ev);
|
||||
List<FloatMenuOption> list = new List<FloatMenuOption>();
|
||||
for (int i = 0; i < (int)max; i += 10)
|
||||
{
|
||||
float level = (float)i;
|
||||
if(level > max) level = max;
|
||||
|
||||
list.Add(new FloatMenuOption(level.ToString("F0"), () => setter(level)));
|
||||
if(level >= max) break;
|
||||
}
|
||||
Find.WindowStack.Add(new FloatMenu(list));
|
||||
}
|
||||
|
||||
public override bool InheritInteractionsFrom(Gizmo other)
|
||||
{
|
||||
if (other is Command_SetTargetFuelLevel otherGizmo)
|
||||
{
|
||||
return getter() == otherGizmo.getter();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Source/ArachnaeSwarm/JobDriver_StartProduction.cs
Normal file
36
Source/ArachnaeSwarm/JobDriver_StartProduction.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_StartProduction : 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);
|
||||
this.FailOnBurningImmobile(BuildingInd);
|
||||
|
||||
yield return Toils_Goto.GotoThing(BuildingInd, PathEndMode.InteractionCell);
|
||||
|
||||
Toil work = ToilMaker.MakeToil("MakeNewToils");
|
||||
work.initAction = delegate
|
||||
{
|
||||
var comp = Building.GetComp<CompInteractiveProducer>();
|
||||
comp.StartProduction();
|
||||
};
|
||||
work.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
yield return work;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user