diff --git a/1.6/1.6/Defs/HediffDefs/ARA_PowerArmor_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/ARA_PowerArmor_Hediffs.xml
new file mode 100644
index 0000000..29f2558
--- /dev/null
+++ b/1.6/1.6/Defs/HediffDefs/ARA_PowerArmor_Hediffs.xml
@@ -0,0 +1,24 @@
+
+
+
+
+ ARA_PowerArmor_NoFuel
+
+ 生物外骨骼因缺少养分而营养不良,这会对宿主造成不良影响.
+ HediffWithComps
+ (0.6, 0.6, 0.6)
+ true
+ false
+
+
+
+
+ Moving
+ -0.4
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/JobDefs/ARA_Jobs.xml b/1.6/1.6/Defs/JobDefs/ARA_Jobs.xml
index 2083d1a..76740e7 100644
--- a/1.6/1.6/Defs/JobDefs/ARA_Jobs.xml
+++ b/1.6/1.6/Defs/JobDefs/ARA_Jobs.xml
@@ -12,4 +12,11 @@
将 TargetA 带到 TargetB.
false
+
+
+ ARA_EnterPowerArmor
+ ArachnaeSwarm.JobDriver_EnterPowerArmor
+ entering TargetA.
+ true
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
index 1a92a1a..ea45ed8 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
@@ -349,6 +349,7 @@
ARA_Latex_Catsuit
ARA_Pantyhose_Black
ARA_Pantyhose_White
+ ARA_SpiderOne_PowerArmor
Apparel_AdvancedHelmet
diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml b/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
new file mode 100644
index 0000000..7d26e4d
--- /dev/null
+++ b/1.6/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
@@ -0,0 +1,127 @@
+
+
+
+
+
+ ARA_Building_SpiderOne
+
+ 阿拉克涅动力装甲
+
+ Graphic_Multi
+ (1,1)
+ ArachnaeSwarm/Apparel/ARA_Bunny_Girl_Uniform
+
+ Building
+ Building
+ PassThroughOnly
+ 70
+ true
+ 0.5
+ false
+ (1,1)
+ Misc
+ true
+ true
+ Normal
+ MapMeshAndRealTime
+ true
+ (0,0,-1)
+
+ 500
+ 2000
+ 50
+ 0.5
+
+
+
+ ARA_SpiderOne_PowerArmor
+
+
+ 10.0
+
+
+ FoodMeals
+ FoodRaw
+
+
+ 1
+ 0.5
+ true
+
+
+
+
+
+ ARA_SpiderOne_PowerArmor
+
+ 阿拉克涅动力装甲
+
+ ARA_Cocoon_Cloth_1Stage
+
+ ArachnaeSwarm.ARA_PowerArmor
+
+
+ 500
+ ARA_Building_SpiderOne
+ ARA_PowerArmor_NoFuel
+ 0.5
+
+
+
+
+ ARA_Technology_6DIL
+ UnfinishedArmor
+
+
+ 25
+
+
+ ArachnaeSwarm/Apparel/ARA_Bunny_Girl_Uniform
+
+
+
+ Torso
+ Shoulders
+ Arms
+ Legs
+
+
+
+ Middle
+
+ ArachnaeSwarm/Apparel/ARA_Bunny_Girl_Uniform
+
+
+ 120
+ 2.5
+
+
+
+ 0
+
+
+ ARA_TerrainMoveSpeedHediff
+
+
+
+ 10.0
+
+
+ FoodMeals
+ FoodRaw
+
+
+ 1
+ 0.5
+ true
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml b/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
new file mode 100644
index 0000000..cac9984
--- /dev/null
+++ b/1.6/Defs/Thing_Misc/ARA_PowerArmor_Defs.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+ Building
+
+ Graphic_Multi
+ (3,3)
+
+ Building
+ PassThroughOnly
+ 70
+ true
+ 0.5
+ false
+ (2,2)
+ Misc
+ true
+ true
+ Never
+ MapMeshAndRealTime
+
+ 250
+ 2000
+ 50
+ 0.5
+
+
+
+
+
+ ArachnaeSwarm.ARA_PowerArmor
+
+ 2
+
+
+ 250
+ 30
+ 0
+ 0.85
+ 0.80
+ 0.90
+ 40
+ 20
+
+
+ -0.5
+
+
+
+ Torso
+ Neck
+ Shoulders
+ Arms
+ Legs
+
+
+ Shell
+ Middle
+
+ false
+
+
+
+
+
+
+
+ ARA_Apparel_SpiderOne
+
+ A prototype power armor with an arachnid design.
+
+ Things/Pawn/Humanlike/Apparel/SpiderArmor/SpiderArmor
+
+
+
+ ARA_Building_SpiderOne
+ 625
+ ARA_PowerArmor_NoFuel
+ 0.5
+
+
+
+
+ 10.0
+
+
+ Meat_Human
+
+
+ FoodMeals
+ FoodRaw
+
+
+ 1
+ 0.5
+ true
+ true
+
+
+
+
+
+ ARA_Building_SpiderOne
+
+ A stationary housing for the Spider-I Power Armor.
+
+ Things/Building/PowerArmorStation
+
+
+
+ ARA_Apparel_SpiderOne
+
+
+ 10.0
+
+
+ Meat_Human
+
+
+ FoodMeals
+ FoodRaw
+
+
+ 1
+ 0.5
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/Languages/English/Keyed/PowerArmor_Keys.xml b/1.6/Languages/English/Keyed/PowerArmor_Keys.xml
new file mode 100644
index 0000000..3257089
--- /dev/null
+++ b/1.6/Languages/English/Keyed/PowerArmor_Keys.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ Enter {0}
+ Cannot enter power armor
+ {0} has been broken!
+
+
+ Structure
+
+
\ No newline at end of file
diff --git a/Languages/ChineseSimplified/Keyed/PowerArmor_Keys.xml b/Languages/ChineseSimplified/Keyed/PowerArmor_Keys.xml
new file mode 100644
index 0000000..73a35af
--- /dev/null
+++ b/Languages/ChineseSimplified/Keyed/PowerArmor_Keys.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ 进入动力甲
+
+
+ 结构点
+
+
+ {0} 已被摧毁!驾驶员 {1} 被暴露在外。
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 2702294..c5701ac 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -267,6 +267,12 @@
+
+
+
+
+
+
diff --git a/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs b/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
new file mode 100644
index 0000000..f30f95b
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
@@ -0,0 +1,252 @@
+using RimWorld;
+using UnityEngine;
+using Verse;
+using System.Collections.Generic;
+
+namespace ArachnaeSwarm
+{
+ public interface IStructurePoints
+ {
+ float StructurePoints { get; }
+ float StructurePointsMax { get; }
+ float StructurePointsPercent { get; }
+ string Label { get; }
+ }
+
+ public class PowerArmorExtension : DefModExtension
+ {
+ public ThingDef buildingDef;
+ public float structurePointsMax = 500f;
+ public HediffDef hediffOnEmptyFuel;
+ public float fuelConsumptionRate = 0.5f; // Nutrition per day
+ }
+
+ [StaticConstructorOnStartup]
+ public class ARA_PowerArmor : Apparel, IStructurePoints
+ {
+ #region Properties
+ private PowerArmorExtension ext;
+ public PowerArmorExtension Ext => ext ??= def.GetModExtension();
+ public override string Label => base.Label;
+
+ private float structurePoints = -1f;
+ public float StructurePointsMax => Ext?.structurePointsMax ?? 500f;
+
+ public float StructurePoints
+ {
+ get
+ {
+ if (structurePoints < 0)
+ {
+ structurePoints = StructurePointsMax;
+ }
+ return structurePoints;
+ }
+ set
+ {
+ structurePoints = Mathf.Clamp(value, 0, StructurePointsMax);
+ }
+ }
+
+ public float StructurePointsPercent => StructurePoints / StructurePointsMax;
+
+ 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();
+ 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()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref structurePoints, "structurePoints", -1f);
+ Scribe_References.Look(ref sourceBuilding, "sourceBuilding");
+ }
+ #endregion
+
+ #region Gizmo
+ public override IEnumerable 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();
+ if (fuelComp != null)
+ {
+ yield return new Gizmo_FuelPanel(fuelComp);
+ }
+ }
+ #endregion
+
+ #region State-Switching
+ public override void Notify_Unequipped(Pawn pawn)
+ {
+ base.Notify_Unequipped(pawn);
+
+ Building building = sourceBuilding;
+
+ // If the source building reference is lost, create a new one as a fallback.
+ if (building == null)
+ {
+ 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);
+ }
+
+ // 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();
+ var buildingFuelComp = building.GetComp();
+ 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
+
+ #region Damage Handling - THE FINAL, CORRECT IMPLEMENTATION
+ public override bool CheckPreAbsorbDamage(DamageInfo dinfo)
+ {
+ if (this.Wearer == null || !dinfo.Def.harmsHealth || dinfo.Amount <= 0.001f)
+ {
+ return false;
+ }
+
+ float finalDamage = GetPostArmorDamage(ref dinfo);
+
+ if (finalDamage > 0)
+ {
+ this.StructurePoints -= finalDamage;
+ EffecterDefOf.DamageDiminished_Metal.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
+
+ if (this.StructurePoints <= 0)
+ {
+ Messages.Message("PowerArmorBroken".Translate(this.Label, this.Wearer.LabelShort), this, MessageTypeDefOf.NegativeEvent);
+ this.Destroy(DestroyMode.KillFinalize);
+ }
+ }
+ else
+ {
+ EffecterDefOf.Deflect_Metal_Bullet.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
+ }
+
+ // By returning true, we tell the game the damage has been fully handled and should not proceed to the pawn.
+ return true;
+ }
+
+ private float GetPostArmorDamage(ref DamageInfo dinfo)
+ {
+ float amount = dinfo.Amount;
+ if (dinfo.Def.armorCategory != null)
+ {
+ StatDef armorRatingStat = dinfo.Def.armorCategory.armorRatingStat;
+ float armorRating = this.GetStatValue(armorRatingStat);
+
+ float armorPenetration = dinfo.ArmorPenetrationInt;
+ float num = Mathf.Max(armorRating - armorPenetration, 0f);
+ float value = Rand.Value;
+ float num2 = num * 0.5f;
+ float num3 = num;
+ if (value < num2)
+ {
+ amount = 0f;
+ }
+ else if (value < num3)
+ {
+ amount = GenMath.RoundRandom(amount / 2f);
+ if (dinfo.Def.armorCategory == DamageArmorCategoryDefOf.Sharp)
+ {
+ dinfo.Def = DamageDefOf.Blunt;
+ }
+ }
+ }
+ return amount;
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
new file mode 100644
index 0000000..7515614
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
@@ -0,0 +1,20 @@
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_PowerArmorStation : CompProperties
+ {
+ public ThingDef apparelDef;
+
+ public CompProperties_PowerArmorStation()
+ {
+ compClass = typeof(CompPowerArmorStation);
+ }
+ }
+
+ public class CompPowerArmorStation : ThingComp
+ {
+ public CompProperties_PowerArmorStation Props => (CompProperties_PowerArmorStation)props;
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/Gizmo_FuelPanel.cs b/Source/ArachnaeSwarm/PowerArmor/Gizmo_FuelPanel.cs
new file mode 100644
index 0000000..ef84748
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/Gizmo_FuelPanel.cs
@@ -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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/Gizmo_StructurePanel.cs b/Source/ArachnaeSwarm/PowerArmor/Gizmo_StructurePanel.cs
new file mode 100644
index 0000000..fc5f566
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/Gizmo_StructurePanel.cs
@@ -0,0 +1,55 @@
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ [StaticConstructorOnStartup]
+ public class Gizmo_StructurePanel : Gizmo
+ {
+ private static readonly Texture2D FullBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.2f));
+ private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f));
+ private static readonly Texture2D UnderflowBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.1f, 0.1f));
+
+ private IStructurePoints armor;
+
+ public Gizmo_StructurePanel(IStructurePoints armor)
+ {
+ this.armor = armor;
+ this.Order = -100f; // Correctly use the 'Order' property
+ }
+
+ 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(984988, 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, armor.Label);
+
+ // Draw bar
+ Rect barRect = rect;
+ barRect.yMin = overRect.height / 2f;
+ float fillPercent = armor.StructurePointsPercent;
+
+ Widgets.FillableBar(barRect, fillPercent, FullBarTex, EmptyBarTex, false);
+
+ // Draw text on bar
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.MiddleCenter;
+ Widgets.Label(barRect, $"{armor.StructurePoints:F0} / {armor.StructurePointsMax:F0}");
+ Text.Anchor = TextAnchor.UpperLeft;
+ });
+ return new GizmoResult(GizmoState.Clear);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs b/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs
new file mode 100644
index 0000000..0ec7543
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/Harmony_ThingWithComps_GetFloatMenuOptions.cs
@@ -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 Postfix(IEnumerable 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();
+
+ 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.GetNamed("ARA_EnterPowerArmor"), __instance);
+ selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+ }
+
+ yield return new FloatMenuOption("EnterPowerArmor".Translate(__instance.Label), enterAction);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs b/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
new file mode 100644
index 0000000..383fe59
--- /dev/null
+++ b/Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
@@ -0,0 +1,68 @@
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class JobDriver_EnterPowerArmor : JobDriver
+ {
+ private const TargetIndex BuildingInd = TargetIndex.A;
+ private Building PowerArmorBuilding => (Building)job.GetTarget(BuildingInd).Thing;
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ return pawn.Reserve(PowerArmorBuilding, job, 1, -1, null, errorOnFailed);
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ this.FailOnDespawnedNullOrForbidden(BuildingInd);
+ this.FailOnSomeonePhysicallyInteracting(BuildingInd);
+
+ yield return Toils_Goto.GotoThing(BuildingInd, PathEndMode.InteractionCell);
+ yield return Toils_General.Wait(120, BuildingInd).WithProgressBarToilDelay(BuildingInd);
+
+ Toil enter = new Toil();
+ enter.initAction = () =>
+ {
+ Pawn actor = enter.actor;
+ var building = (Building)actor.CurJob.GetTarget(BuildingInd).Thing;
+
+ // Get the CompProperties from the building's new component
+ var compProps = building.GetComp()?.Props;
+ if (compProps != null && compProps.apparelDef != null)
+ {
+ // Create the apparel
+ ARA_PowerArmor apparel = (ARA_PowerArmor)ThingMaker.MakeThing(compProps.apparelDef);
+
+ // CRITICAL STEP: Link the apparel back to the building
+ apparel.sourceBuilding = building;
+
+ // Sync health from building to apparel
+ apparel.StructurePoints = building.HitPoints;
+
+ // Sync fuel from building to apparel
+ var buildingFuelComp = building.GetComp();
+ var apparelFuelComp = apparel.GetComp();
+ if (buildingFuelComp != null && apparelFuelComp != null)
+ {
+ apparelFuelComp.ReceiveFuel(buildingFuelComp.Fuel);
+ }
+
+ // Wear the apparel
+ actor.apparel.Wear(apparel, true, true);
+
+ // Despawn the building
+ building.DeSpawn();
+ }
+ else
+ {
+ Log.Error($"[ArachnaeSwarm] Power Armor Building {building.def.defName} is missing CompProperties_PowerArmorStation or apparelDef.");
+ }
+ };
+ enter.defaultCompleteMode = ToilCompleteMode.Instant;
+ yield return enter;
+ }
+ }
+}
\ No newline at end of file