暂存
This commit is contained in:
@@ -271,6 +271,8 @@
|
||||
<Compile Include="PowerArmor\CompPowerArmorStation.cs" />
|
||||
<Compile Include="PowerArmor\Gizmo_StructurePanel.cs" />
|
||||
<Compile Include="PowerArmor\JobDriver_EnterPowerArmor.cs" />
|
||||
<Compile Include="PowerArmor\Gizmo_FuelPanel.cs" />
|
||||
<Compile Include="PowerArmor\Harmony_ThingWithComps_GetFloatMenuOptions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Jobs\JobDriver_SuperCarry\SuperCarryExtension.cs" />
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
public ThingDef buildingDef;
|
||||
public float structurePointsMax = 500f;
|
||||
public HediffDef hediffOnEmptyFuel;
|
||||
public float fuelConsumptionRate = 0.5f; // Nutrition per day
|
||||
}
|
||||
|
||||
[StaticConstructorOnStartup]
|
||||
@@ -51,6 +53,57 @@ namespace ArachnaeSwarm
|
||||
public Building sourceBuilding;
|
||||
#endregion
|
||||
|
||||
#region Ticker
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick(); // Call Apparel's Tick
|
||||
|
||||
if (this.Wearer == null) return; // Only tick if worn
|
||||
|
||||
var fuelComp = this.GetComp<CompRefuelableNutrition>();
|
||||
if (fuelComp != null)
|
||||
{
|
||||
// Explicitly call the component's Tick method to ensure fuel consumption logic is executed.
|
||||
// This is needed because Apparel's base Tick does not automatically call component Ticks.
|
||||
// First, update consumption rate and hediffs
|
||||
if (this.Wearer.IsHashIntervalTick(60)) // Check every second
|
||||
{
|
||||
if (this.Wearer.pather != null && this.Wearer.pather.MovingNow)
|
||||
{
|
||||
fuelComp.currentConsumptionRate = Ext?.fuelConsumptionRate ?? 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fuelComp.currentConsumptionRate = 0f;
|
||||
}
|
||||
|
||||
// Handle hediff for empty fuel
|
||||
var hediffDef = Ext?.hediffOnEmptyFuel;
|
||||
if (hediffDef != null)
|
||||
{
|
||||
var hediff = this.Wearer.health.hediffSet.GetFirstHediffOfDef(hediffDef);
|
||||
if (!fuelComp.HasFuel)
|
||||
{
|
||||
if (hediff == null)
|
||||
{
|
||||
this.Wearer.health.AddHediff(hediffDef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hediff != null)
|
||||
{
|
||||
this.Wearer.health.RemoveHediff(hediff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then, explicitly call the component's Tick method to ensure fuel consumption logic is executed with the UPDATED rate.
|
||||
fuelComp.CompTick();
|
||||
}
|
||||
} // Correctly close the Tick method
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
public override void ExposeData()
|
||||
{
|
||||
@@ -63,11 +116,21 @@ namespace ArachnaeSwarm
|
||||
#region Gizmo
|
||||
public override IEnumerable<Gizmo> GetWornGizmos()
|
||||
{
|
||||
// Always yield base gizmos first.
|
||||
foreach (var gizmo in base.GetWornGizmos())
|
||||
{
|
||||
yield return gizmo;
|
||||
}
|
||||
|
||||
// Yield our custom structure points gizmo.
|
||||
yield return new Gizmo_StructurePanel(this);
|
||||
|
||||
// Yield our custom fuel panel gizmo.
|
||||
var fuelComp = this.GetComp<CompRefuelableNutrition>();
|
||||
if (fuelComp != null)
|
||||
{
|
||||
yield return new Gizmo_FuelPanel(fuelComp);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -76,17 +139,53 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
base.Notify_Unequipped(pawn);
|
||||
|
||||
ThingDef buildingToSpawn = sourceBuilding?.def ?? Ext?.buildingDef;
|
||||
Building building = sourceBuilding;
|
||||
|
||||
if (buildingToSpawn == null)
|
||||
// If the source building reference is lost, create a new one as a fallback.
|
||||
if (building == null)
|
||||
{
|
||||
Log.Error($"[ArachnaeSwarm] Power Armor {this.def.defName} unequipped, but has no buildingDef defined in its PowerArmorExtension or a source building.");
|
||||
return;
|
||||
ThingDef buildingDef = Ext?.buildingDef;
|
||||
if (buildingDef == null)
|
||||
{
|
||||
Log.Error($"[ArachnaeSwarm] Power Armor {this.def.defName} unequipped, but has no buildingDef defined in its PowerArmorExtension and the source building reference was lost.");
|
||||
this.Destroy(DestroyMode.Vanish);
|
||||
return;
|
||||
}
|
||||
building = (Building)ThingMaker.MakeThing(buildingDef);
|
||||
}
|
||||
|
||||
Building building = (Building)ThingMaker.MakeThing(buildingToSpawn);
|
||||
building.HitPoints = Mathf.RoundToInt(this.StructurePoints);
|
||||
// Sync health back to the building, ensuring it's at least 1 to prevent it from being destroyed instantly.
|
||||
building.HitPoints = Mathf.Max(1, Mathf.RoundToInt(this.StructurePoints));
|
||||
|
||||
// Sync fuel back to the building
|
||||
var apparelFuelComp = this.GetComp<CompRefuelableNutrition>();
|
||||
var buildingFuelComp = building.GetComp<CompRefuelableNutrition>();
|
||||
if (apparelFuelComp != null && buildingFuelComp != null)
|
||||
{
|
||||
// Reset building fuel and then set it to the apparel's current fuel to avoid overflow.
|
||||
buildingFuelComp.ConsumeFuel(buildingFuelComp.Fuel);
|
||||
buildingFuelComp.ReceiveFuel(apparelFuelComp.Fuel);
|
||||
}
|
||||
|
||||
Log.Message($"[PA_Debug] Notify_Unequipped: Before spawning building (ID: {building.thingIDNumber}) - HitPoints: {building.HitPoints}, StackCount: {building.stackCount}");
|
||||
|
||||
// Ensure stackCount is at least 1 for buildings, as 0 stackCount causes errors during spawning
|
||||
if (building.stackCount <= 0)
|
||||
{
|
||||
building.stackCount = 1;
|
||||
Log.Warning($"[PA_Debug] Notify_Unequipped: Corrected building (ID: {building.thingIDNumber}) stackCount to 1 as it was 0.");
|
||||
}
|
||||
|
||||
// Set the faction to the pawn's faction before spawning
|
||||
building.SetFaction(pawn.Faction);
|
||||
|
||||
// Re-spawn the original building instance
|
||||
GenPlace.TryPlaceThing(building, pawn.Position, pawn.Map, ThingPlaceMode.Near);
|
||||
Log.Message($"[PA_Debug] Notify_Unequipped: After spawning building (ID: {building.thingIDNumber}) - HitPoints: {building.HitPoints}, StackCount: {building.stackCount}");
|
||||
|
||||
// Destroy the apparel to prevent duplication
|
||||
this.Destroy(DestroyMode.Vanish);
|
||||
Log.Message($"[PA_Debug] Notify_Unequipped: Apparel {this.Label} (ID: {this.thingIDNumber}) destroyed.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
55
Source/ArachnaeSwarm/PowerArmor/Gizmo_FuelPanel.cs
Normal file
55
Source/ArachnaeSwarm/PowerArmor/Gizmo_FuelPanel.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using RimWorld; // For SolidColorMaterials
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public class Gizmo_FuelPanel : Gizmo
|
||||
{
|
||||
private static readonly Texture2D FullBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.7f, 0.2f)); // Orange for fuel
|
||||
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f));
|
||||
|
||||
private CompRefuelableNutrition fuelComp;
|
||||
|
||||
public Gizmo_FuelPanel(CompRefuelableNutrition fuelComp)
|
||||
{
|
||||
this.fuelComp = fuelComp;
|
||||
this.Order = -90f; // Slightly higher order than structure panel
|
||||
}
|
||||
|
||||
public override float GetWidth(float maxWidth)
|
||||
{
|
||||
return 140f;
|
||||
}
|
||||
|
||||
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
|
||||
{
|
||||
Rect overRect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
|
||||
Find.WindowStack.ImmediateWindow(984989, overRect, WindowLayer.GameUI, delegate
|
||||
{
|
||||
Rect rect = overRect.AtZero().ContractedBy(6f);
|
||||
|
||||
// Draw label
|
||||
Rect labelRect = rect;
|
||||
labelRect.height = overRect.height / 2f;
|
||||
Text.Font = GameFont.Tiny;
|
||||
Widgets.Label(labelRect, "Fuel".Translate()); // Use "Fuel" or custom text
|
||||
|
||||
// Draw bar
|
||||
Rect barRect = rect;
|
||||
barRect.yMin = overRect.height / 2f;
|
||||
float fillPercent = fuelComp.FuelPercentOfMax;
|
||||
|
||||
Widgets.FillableBar(barRect, fillPercent, FullBarTex, EmptyBarTex, false);
|
||||
|
||||
// Draw text on bar
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(barRect, $"{fuelComp.Fuel:F0} / {fuelComp.Props.fuelCapacity:F0}");
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
});
|
||||
return new GizmoResult(GizmoState.Clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using HarmonyLib;
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
[HarmonyPatch(typeof(ThingWithComps), "GetFloatMenuOptions")]
|
||||
public static class Harmony_ThingWithComps_GetFloatMenuOptions
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static IEnumerable<FloatMenuOption> Postfix(IEnumerable<FloatMenuOption> values, ThingWithComps __instance, Pawn selPawn)
|
||||
{
|
||||
// First, return all original options
|
||||
foreach (var value in values)
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
|
||||
// --- DEBUG LOGGING ---
|
||||
// Use a more specific check to avoid log spam
|
||||
if (__instance.def.defName != null && __instance.def.defName.StartsWith("ARA_"))
|
||||
{
|
||||
Log.Message($"[PA_Debug] GetFloatMenuOptions Postfix triggered for: {__instance.def.defName}");
|
||||
}
|
||||
|
||||
// Check if the thing is our power armor building
|
||||
var comp = __instance.GetComp<CompPowerArmorStation>();
|
||||
|
||||
if (comp == null && __instance.def.defName != null && __instance.def.defName.StartsWith("ARA_"))
|
||||
{
|
||||
Log.Message($"[PA_Debug] CompPowerArmorStation is NULL for {__instance.def.defName}");
|
||||
}
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
Log.Message($"[PA_Debug] CompPowerArmorStation FOUND for {__instance.def.defName}. Checking reachability.");
|
||||
|
||||
// Check if the pawn can interact
|
||||
if (!selPawn.CanReserveAndReach(__instance, PathEndMode.InteractionCell, Danger.Deadly))
|
||||
{
|
||||
yield return new FloatMenuOption("CannotEnterPowerArmor".Translate() + ": " + "CannotReach".Translate(), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Action to give the job
|
||||
void enterAction()
|
||||
{
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_EnterPowerArmor"), __instance);
|
||||
selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||
}
|
||||
|
||||
yield return new FloatMenuOption("EnterPowerArmor".Translate(__instance.Label), enterAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,14 @@ namespace ArachnaeSwarm
|
||||
// Sync health from building to apparel
|
||||
apparel.StructurePoints = building.HitPoints;
|
||||
|
||||
// Sync fuel from building to apparel
|
||||
var buildingFuelComp = building.GetComp<CompRefuelableNutrition>();
|
||||
var apparelFuelComp = apparel.GetComp<CompRefuelableNutrition>();
|
||||
if (buildingFuelComp != null && apparelFuelComp != null)
|
||||
{
|
||||
apparelFuelComp.ReceiveFuel(buildingFuelComp.Fuel);
|
||||
}
|
||||
|
||||
// Wear the apparel
|
||||
actor.apparel.Wear(apparel, true, true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user