This commit is contained in:
2025-09-24 12:08:27 +08:00
parent ae4a2e0f99
commit a76355fd83
10 changed files with 505 additions and 133 deletions

View File

@@ -128,6 +128,7 @@
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\CompRefuelableWithKey.cs" />
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\IFuelSource.cs" />
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\Patch_CompRefuelableWithKey.cs" />
<Compile Include="Building_Comps\CompNutritionToFuelConverter.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\Hediff_ConfigurableMutant.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\Hediff_NecroticVirus_Configurable.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\HediffComp_NecroticTransformation.cs" />
@@ -203,6 +204,7 @@
<Compile Include="Verbs\Verb_ShootArc.cs" />
<Compile Include="Verbs\Verb_ShootMeltBeam.cs" />
<Compile Include="Verbs\Verb_ShootShotgun.cs" />
<Compile Include="Verbs\Verb_ShootConsumeNutrition.cs" />
<Compile Include="Verbs\VerbProperties_Excalibur.cs" />
<Compile Include="Verbs\Verb_ShootSprayMulti.cs" />
<Compile Include="Verbs\WeaponStealBeam\Verb_ShootWeaponStealBeam.cs" />

View File

@@ -76,7 +76,8 @@ namespace ArachnaeSwarm
public override string CompInspectStringExtra()
{
string text = Props.FuelLabel + ": " + Fuel.ToStringDecimalIfSmall() + " / " + Props.fuelCapacity.ToStringDecimalIfSmall();
string fuelLabel = string.IsNullOrEmpty(Props.FuelLabel) ? "Nutrition" : Props.FuelLabel;
string text = fuelLabel + ": " + Fuel.ToStringDecimalIfSmall() + " / " + Props.fuelCapacity.ToStringDecimalIfSmall();
if (currentConsumptionRate > 0f && HasFuel)
{

View File

@@ -0,0 +1,125 @@
using RimWorld;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_NutritionToFuelConverter : CompProperties
{
public int checkInterval = 240;
public float nutritionCost = 20f;
public int workAmount = 6000;
public float fuelAmount = 1f;
public CompProperties_NutritionToFuelConverter()
{
compClass = typeof(CompNutritionToFuelConverter);
}
}
public class CompNutritionToFuelConverter : ThingComp
{
private CompRefuelableNutrition nutritionComp;
private CompRefuelable fuelComp;
public float nutritionProgress = 0f;
public float workProgress = 0f;
private CompProperties_NutritionToFuelConverter Props => (CompProperties_NutritionToFuelConverter)props;
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
nutritionComp = parent.GetComp<CompRefuelableNutrition>();
fuelComp = parent.GetComp<CompRefuelable>();
if (nutritionComp == null)
{
Log.Error($"[ArachnaeSwarm] {parent.def.defName} has CompNutritionToFuelConverter but no CompRefuelableNutrition.");
}
if (fuelComp == null)
{
Log.Error($"[ArachnaeSwarm] {parent.def.defName} has CompNutritionToFuelConverter but no CompRefuelable.");
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref nutritionProgress, "nutritionProgress", 0f);
Scribe_Values.Look(ref workProgress, "workProgress", 0f);
}
public override void CompTick()
{
base.CompTick();
if (parent.IsHashIntervalTick(Props.checkInterval))
{
TryProcess();
}
}
private void TryProcess()
{
if (fuelComp == null || fuelComp.IsFull)
{
return;
}
// Stage 1: Gather nutrition
if (nutritionProgress < Props.nutritionCost)
{
if (nutritionComp != null && nutritionComp.Fuel > 0)
{
float needed = Props.nutritionCost - nutritionProgress;
float canTake = System.Math.Min(needed, nutritionComp.Fuel);
nutritionComp.ConsumeFuel(canTake);
nutritionProgress += canTake;
}
// Reset work progress if we are still gathering nutrition
workProgress = 0;
return;
}
// Stage 2: Process work
workProgress += Props.checkInterval;
// Stage 3: Finish crafting
if (workProgress >= Props.workAmount)
{
int unitsToCraft = (int)(workProgress / Props.workAmount);
float totalFuel = unitsToCraft * Props.fuelAmount;
float spaceInTank = fuelComp.Props.fuelCapacity - fuelComp.Fuel;
if (totalFuel > spaceInTank)
{
totalFuel = spaceInTank;
unitsToCraft = (int)(totalFuel / Props.fuelAmount);
}
if (unitsToCraft > 0)
{
fuelComp.Refuel(unitsToCraft * Props.fuelAmount);
nutritionProgress -= unitsToCraft * Props.nutritionCost;
workProgress -= unitsToCraft * Props.workAmount;
}
}
}
public override string CompInspectStringExtra()
{
if (fuelComp == null) return null;
if (fuelComp.IsFull)
{
return "ARA_NutritionConverter_State_TankFull".Translate();
}
if (nutritionProgress < Props.nutritionCost)
{
return "ARA_NutritionConverter_Gathering".Translate(nutritionProgress.ToString("F1"), Props.nutritionCost);
}
return "ARA_NutritionConverter_Working".Translate(workProgress.ToString("F0"), Props.workAmount);
}
}
}

View File

@@ -0,0 +1,41 @@
using RimWorld;
using Verse;
namespace ArachnaeSwarm
{
public class Verb_ShootConsumeNutrition : Verb_Shoot
{
public override bool Available()
{
if (!base.Available())
{
return false;
}
if (verbProps.consumeFuelPerShot > 0f)
{
CompRefuelableNutrition comp = caster.TryGetComp<CompRefuelableNutrition>();
if (comp != null && comp.Fuel < verbProps.consumeFuelPerShot)
{
return false;
}
}
return true;
}
public override void WarmupComplete()
{
// This is a bit of a workaround. The base WarmupComplete calls TryCastNextBurstShot,
// which in turn calls the base Verb's fuel consumption logic before we can intervene.
// So we consume fuel here, and the base call will find it already consumed.
// This relies on the fact that TryCastNextBurstShot in the base Verb class checks fuel again.
if (verbProps.consumeFuelPerShot > 0f)
{
caster.TryGetComp<CompRefuelableNutrition>()?.ConsumeFuel(verbProps.consumeFuelPerShot);
}
base.WarmupComplete();
}
}
}