+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
index 6504763..80715f5 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
@@ -299,8 +299,9 @@
Heavy
-
- 100
+
+ nutrition
+ 5.0
ARA_InsectJelly
@@ -451,8 +452,9 @@
Heavy
-
- 20
+
+ nutrition
+ 5.0
ARA_InsectJelly
@@ -623,8 +625,9 @@
Normal
-
- 10
+
+ nutrition
+ 5.0
ARA_InsectJelly
diff --git a/1.6/1.6/Defs/WorkGiverDefs/ARA_WorkGivers.xml b/1.6/1.6/Defs/WorkGiverDefs/ARA_WorkGivers.xml
new file mode 100644
index 0000000..725e3a7
--- /dev/null
+++ b/1.6/1.6/Defs/WorkGiverDefs/ARA_WorkGivers.xml
@@ -0,0 +1,14 @@
+
+
+
+ ARA_Refuel_Nutrition
+
+ ArachnaeSwarm.WorkGiver_Refuel_Nutrition
+ Hauling
+ 60
+ 补充
+ 补充
+ true
+ false
+
+
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 10cd203..0dc2f96 100644
Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
index 8b315da..c99f45a 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -1,22 +1,29 @@
{
"Version": 1,
- "WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
+ "WorkspaceRootPath": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\thingcomp_guardianpsyfield.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thingcomp_guardianpsyfield.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_supercarry\\floatmenuoptionprovider_supercarry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_supercarry\\floatmenuoptionprovider_supercarry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\thing_comps\\ara_thingcomp_guardianpsyfield\\harmony_projectileinterceptor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_thingcomp_guardianpsyfield\\harmony_projectileinterceptor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\thing_comps\\ara_thingcomp_guardianpsyfield\\thingcomp_guardianpsyfield.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_thingcomp_guardianpsyfield\\thingcomp_guardianpsyfield.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_nutrientnetwork\\compnutrientprovider.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_nutrientnetwork\\compnutrientprovider.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_nutrientnetwork\\compnutrientprovider.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_nutrientnetwork\\complinedrawer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_nutrientnetwork\\complinedrawer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompLineDrawer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -35,23 +42,49 @@
{
"$type": "Document",
"DocumentIndex": 0,
+ "Title": "FloatMenuOptionProvider_SuperCarry.cs",
+ "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SuperCarry\\FloatMenuOptionProvider_SuperCarry.cs",
+ "RelativeDocumentMoniker": "Jobs\\JobDriver_SuperCarry\\FloatMenuOptionProvider_SuperCarry.cs",
+ "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SuperCarry\\FloatMenuOptionProvider_SuperCarry.cs",
+ "RelativeToolTip": "Jobs\\JobDriver_SuperCarry\\FloatMenuOptionProvider_SuperCarry.cs",
+ "ViewState": "AQIAAAAAAAAAAAAAAADwvwAAAAAAAAAA",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-10-04T07:00:14.106Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "Harmony_ProjectileInterceptor.cs",
+ "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_ThingComp_GuardianPsyField\\Harmony_ProjectileInterceptor.cs",
+ "RelativeDocumentMoniker": "Thing_Comps\\ARA_ThingComp_GuardianPsyField\\Harmony_ProjectileInterceptor.cs",
+ "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_ThingComp_GuardianPsyField\\Harmony_ProjectileInterceptor.cs",
+ "RelativeToolTip": "Thing_Comps\\ARA_ThingComp_GuardianPsyField\\Harmony_ProjectileInterceptor.cs",
+ "ViewState": "AQIAAAAAAAAAAAAAAADwvwAAAAAAAAAA",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-10-04T07:00:14.029Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
"Title": "ThingComp_GuardianPsyField.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ThingComp_GuardianPsyField.cs",
- "RelativeDocumentMoniker": "ThingComp_GuardianPsyField.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ThingComp_GuardianPsyField.cs",
- "RelativeToolTip": "ThingComp_GuardianPsyField.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAAgAAAAAAAAAA==",
+ "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_ThingComp_GuardianPsyField\\ThingComp_GuardianPsyField.cs",
+ "RelativeDocumentMoniker": "Thing_Comps\\ARA_ThingComp_GuardianPsyField\\ThingComp_GuardianPsyField.cs",
+ "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_ThingComp_GuardianPsyField\\ThingComp_GuardianPsyField.cs",
+ "RelativeToolTip": "Thing_Comps\\ARA_ThingComp_GuardianPsyField\\ThingComp_GuardianPsyField.cs",
+ "ViewState": "AQIAAAAAAAAAAAAAAADwvwAAAAAAAAAA",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-02T16:24:06.176Z",
"EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 1,
+ "DocumentIndex": 3,
"Title": "Building_NutrientVat.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
+ "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
+ "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"RelativeToolTip": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"ViewState": "AgIAAF8AAAAAAAAAAAAswJkBAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
@@ -59,11 +92,11 @@
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 4,
"Title": "CompNutrientProvider.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
+ "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
+ "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
"RelativeToolTip": "Building_Comps\\ARA_NutrientNetwork\\CompNutrientProvider.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABkAAAAZAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
@@ -71,12 +104,10 @@
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 5,
"Title": "CompLineDrawer.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompLineDrawer.cs",
- "RelativeDocumentMoniker": "Building_Comps\\ARA_NutrientNetwork\\CompLineDrawer.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientNetwork\\CompLineDrawer.cs",
- "RelativeToolTip": "Building_Comps\\ARA_NutrientNetwork\\CompLineDrawer.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABkAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-02T15:11:03.083Z"
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 1409dca..06637fc 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -128,7 +128,6 @@
-
@@ -146,6 +145,9 @@
+
+
+
@@ -171,13 +173,13 @@
-
-
+
+
-
-
+
+
@@ -250,9 +252,9 @@
-
-
-
+
+
+
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompLineDrawer.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompLineDrawer.cs
deleted file mode 100644
index f5c7d8a..0000000
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompLineDrawer.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using RimWorld;
-using Verse;
-using UnityEngine;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace ArachnaeSwarm
-{
- public class CompProperties_LineDrawer : CompProperties
- {
- public List linkableBuildings;
- public float maxDistance = 999f;
- public string lineTexturePath = "Things/Special/Power/Wire";
-
- public CompProperties_LineDrawer()
- {
- compClass = typeof(CompLineDrawer);
- }
- }
-
- public class CompLineDrawer : ThingComp
- {
- private CompProperties_LineDrawer Props => (CompProperties_LineDrawer)props;
- private List linkedBuildings = new List();
- private Material lineMat;
-
- private Material LineMat
- {
- get
- {
- if (lineMat == null)
- {
- lineMat = MaterialPool.MatFrom(Props.lineTexturePath, ShaderDatabase.Transparent, Color.white);
- }
- return lineMat;
- }
- }
-
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
- FindAndLinkBuildings();
- }
-
- public override void CompTick()
- {
- base.CompTick();
- if (parent.IsHashIntervalTick(120))
- {
- FindAndLinkBuildings();
- }
- }
-
- private void FindAndLinkBuildings()
- {
- int previousCount = linkedBuildings.Count;
-
- linkedBuildings.Clear();
- if (Props.linkableBuildings.NullOrEmpty()) return;
-
- var potentialTargets = parent.Map.listerBuildings.allBuildingsColonist.Where(b =>
- b != parent &&
- Props.linkableBuildings.Contains(b.def) &&
- parent.Position.DistanceTo(b.Position) <= Props.maxDistance &&
- HasLineOfSight(parent, b) // 新增:检查视线
- );
-
- linkedBuildings.AddRange(potentialTargets);
-
- if (linkedBuildings.Count != previousCount)
- {
- parent.Map.mapDrawer.MapMeshDirty(parent.Position, MapMeshFlagDefOf.Things, true, false);
- }
- }
-
- // 修复后的方法:检查两点之间是否有墙体遮挡
- private bool HasLineOfSight(Thing from, Thing to)
- {
- IntVec3 fromPos = from.Position;
- IntVec3 toPos = to.Position;
-
- // 如果两个建筑在同一位置,直接返回true
- if (fromPos == toPos) return true;
-
- // 使用更兼容的视线检查方法
- if (!GenSight.LineOfSight(fromPos, toPos, parent.Map))
- {
- return false;
- }
-
- // 额外检查:确保路径上没有阻挡视线的建筑
- foreach (IntVec3 cell in GetLineCells(fromPos, toPos))
- {
- // 跳过起点和终点
- if (cell == fromPos || cell == toPos) continue;
-
- // 检查该单元格是否有阻挡视线的建筑
- List things = parent.Map.thingGrid.ThingsListAt(cell);
- foreach (Thing thing in things)
- {
- // 如果是建筑且阻挡视线
- if (thing.def.passability == Traversability.Impassable &&
- thing.def.category == ThingCategory.Building &&
- !IsPassableBuilding(thing.def)) // 排除可通行的建筑类型
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- // 获取两点之间的直线上的所有单元格
- private IEnumerable GetLineCells(IntVec3 start, IntVec3 end)
- {
- // 使用简单的Bresenham直线算法
- int x0 = start.x;
- int y0 = start.z;
- int x1 = end.x;
- int y1 = end.z;
-
- int dx = Mathf.Abs(x1 - x0);
- int dy = Mathf.Abs(y1 - y0);
- int sx = x0 < x1 ? 1 : -1;
- int sy = y0 < y1 ? 1 : -1;
- int err = dx - dy;
-
- while (true)
- {
- yield return new IntVec3(x0, 0, y0);
-
- if (x0 == x1 && y0 == y1) break;
-
- int e2 = 2 * err;
- if (e2 > -dy)
- {
- err -= dy;
- x0 += sx;
- }
- if (e2 < dx)
- {
- err += dx;
- y0 += sy;
- }
- }
- }
-
- // 检查建筑类型是否允许管线通过
- private bool IsPassableBuilding(ThingDef def)
- {
- // 门、栅栏门等可通行的建筑不算阻挡
- return def.IsDoor ||
- def.passability == Traversability.PassThroughOnly ||
- def.passability == Traversability.Standable;
- }
-
- public override void PostPrintOnto(SectionLayer layer)
- {
- base.PostPrintOnto(layer);
- foreach (var building in linkedBuildings)
- {
- Vector3 center = (this.parent.TrueCenter() + this.parent.Graphic.DrawOffset(this.parent.Rotation) + building.TrueCenter() + building.Graphic.DrawOffset(building.Rotation)) / 2f;
- center.y = AltitudeLayer.SmallWire.AltitudeFor();
- Vector3 v = building.TrueCenter() - this.parent.TrueCenter();
- Vector2 size = new Vector2(1f, v.MagnitudeHorizontal());
- float rot = v.AngleFlat();
- Printer_Plane.PrintPlane(layer, center, size, this.LineMat, rot);
- }
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompNutrientProvider.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompNutrientProvider.cs
index ea11cb1..3043bd1 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompNutrientProvider.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompNutrientProvider.cs
@@ -11,6 +11,19 @@ namespace ArachnaeSwarm
{
private CompRefuelableNutrition selfRefuelable;
private new CompProperties_NutrientProvider Props => (CompProperties_NutrientProvider)props;
+ private Material lineMat;
+
+ private Material LineMat
+ {
+ get
+ {
+ if (lineMat == null)
+ {
+ lineMat = MaterialPool.MatFrom(Props.lineTexturePath, ShaderDatabase.Transparent, Color.white);
+ }
+ return lineMat;
+ }
+ }
public override void PostSpawnSetup(bool respawningAfterLoad)
{
@@ -102,5 +115,20 @@ namespace ArachnaeSwarm
}
return comp.TargetFuelLevel;
}
+
+ public override void PostPrintOnto(SectionLayer layer)
+ {
+ base.PostPrintOnto(layer);
+ foreach (var building in LinkedBuildings)
+ {
+ if (building == null) continue;
+ Vector3 center = (this.parent.TrueCenter() + this.parent.Graphic.DrawOffset(this.parent.Rotation) + building.TrueCenter() + building.Graphic.DrawOffset(building.Rotation)) / 2f;
+ center.y = AltitudeLayer.SmallWire.AltitudeFor();
+ Vector3 v = building.TrueCenter() - this.parent.TrueCenter();
+ Vector2 size = new Vector2(1f, v.MagnitudeHorizontal());
+ float rot = v.AngleFlat();
+ Printer_Plane.PrintPlane(layer, center, size, this.LineMat, rot);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompProperties_NutrientProvider.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompProperties_NutrientProvider.cs
index 34a1764..7a47931 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompProperties_NutrientProvider.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompProperties_NutrientProvider.cs
@@ -5,6 +5,8 @@ namespace ArachnaeSwarm
public class CompProperties_NutrientProvider : CompProperties_Facility
{
public float maxEfficiency = 0.9f;
+ public string lineTexturePath = "Things/Special/Power/Wire";
+
public CompProperties_NutrientProvider()
{
compClass = typeof(CompNutrientProvider);
diff --git a/Source/ArachnaeSwarm/Building_Comps/CompAutoEjector.cs b/Source/ArachnaeSwarm/Building_Comps/CompAutoEjector.cs
new file mode 100644
index 0000000..411fa1a
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Comps/CompAutoEjector.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ // Properties for the new component
+ public class CompProperties_AutoEjector : CompProperties
+ {
+ public int checkInterval = 250; // Check roughly every 4 seconds
+ public float ejectAtPercent = 1.0f; // Eject when fuel reaches this percentage of max capacity (1.0 = 100%)
+ public Type targetComp = typeof(CompRefuelable); // The specific CompRefuelable class to target, can be overridden in XML
+
+ public CompProperties_AutoEjector()
+ {
+ this.compClass = typeof(CompAutoEjector);
+ }
+ }
+
+ // The component logic
+ public class CompAutoEjector : ThingComp
+ {
+ private CompProperties_AutoEjector Props => (CompProperties_AutoEjector)this.props;
+ private CompRefuelable refuelableComp;
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ // Find the specific refuelable component specified in XML
+ this.refuelableComp = this.parent.GetComps()
+ .FirstOrDefault(comp => comp.GetType() == this.Props.targetComp);
+
+ if (this.refuelableComp == null)
+ {
+ Log.Warning($"[ArachnaeSwarm] CompAutoEjector on {parent.def.defName} could not find a CompRefuelable of type '{this.Props.targetComp.FullName}' to monitor.");
+ }
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ // Check if we have a valid refuelable comp and it's time to check
+ if (this.refuelableComp != null &&
+ this.parent.IsHashIntervalTick(this.Props.checkInterval))
+ {
+ // Check if fuel has reached or exceeded the configured percentage of the MAX capacity
+ if (this.refuelableComp.FuelPercentOfMax >= this.Props.ejectAtPercent)
+ {
+ // Call the public EjectFuel() method.
+ this.refuelableComp.EjectFuel();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Building_Comps/CompRefuelableNutrition.cs b/Source/ArachnaeSwarm/Building_Comps/CompRefuelableNutrition.cs
index 3d0283c..e9e153f 100644
--- a/Source/ArachnaeSwarm/Building_Comps/CompRefuelableNutrition.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/CompRefuelableNutrition.cs
@@ -63,10 +63,7 @@ namespace ArachnaeSwarm
fuelNeeded = TargetFuelLevel - Fuel;
}
- if (totalNutritionGained > 0 && Props.fuelGizmoLabel != null)
- {
- Messages.Message("MessageRefueled".Translate(parent.LabelShort, totalNutritionGained.ToString("0.##"), Props.fuelGizmoLabel), parent, MessageTypeDefOf.PositiveEvent);
- }
+ // Let the job driver handle the message. This component should only handle logic.
}
public void ReceiveFuel(float amount)
diff --git a/Source/ArachnaeSwarm/Building_Comps/WULA_MutiFuelSpawner/CompRefuelableWithKey.cs b/Source/ArachnaeSwarm/Building_Comps/WULA_MutiFuelSpawner/CompRefuelableWithKey.cs
index 39e4107..388ebda 100644
--- a/Source/ArachnaeSwarm/Building_Comps/WULA_MutiFuelSpawner/CompRefuelableWithKey.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/WULA_MutiFuelSpawner/CompRefuelableWithKey.cs
@@ -1,5 +1,7 @@
using RimWorld;
using Verse;
+using System.Reflection;
+using HarmonyLib;
namespace ArachnaeSwarm
{
@@ -17,6 +19,36 @@ namespace ArachnaeSwarm
{
public new CompProperties_RefuelableWithKey Props => (CompProperties_RefuelableWithKey)props;
+ public override void PostExposeData()
+ {
+ string prefix = Props.saveKeysPrefix;
+ if (prefix.NullOrEmpty())
+ {
+ Log.ErrorOnce($"CompRefuelableWithKey on {parent.def.defName} has a null or empty saveKeysPrefix. Defaulting to standard save.", GetHashCode());
+ base.PostExposeData();
+ return;
+ }
+
+ FieldInfo fuelField = AccessTools.Field(typeof(CompRefuelable), "fuel");
+ FieldInfo configuredTargetFuelLevelField = AccessTools.Field(typeof(CompRefuelable), "configuredTargetFuelLevel");
+ FieldInfo allowAutoRefuelField = AccessTools.Field(typeof(CompRefuelable), "allowAutoRefuel");
+
+ float currentFuel = (float)fuelField.GetValue(this);
+ float currentConfiguredLevel = (float)configuredTargetFuelLevelField.GetValue(this);
+ bool currentAllowAuto = (bool)allowAutoRefuelField.GetValue(this);
+
+ Scribe_Values.Look(ref currentFuel, prefix + "_fuel", 0f);
+ Scribe_Values.Look(ref currentConfiguredLevel, prefix + "_configuredTargetFuelLevel", -1f);
+ Scribe_Values.Look(ref currentAllowAuto, prefix + "_allowAutoRefuel", true);
+
+ if (Scribe.mode == LoadSaveMode.LoadingVars)
+ {
+ fuelField.SetValue(this, currentFuel);
+ configuredTargetFuelLevelField.SetValue(this, currentConfiguredLevel);
+ allowAutoRefuelField.SetValue(this, currentAllowAuto);
+ }
+ }
+
public new void Notify_UsedThisTick()
{
if (Props.consumeFuelOnlyWhenUsed)
diff --git a/Source/ArachnaeSwarm/JobDriver_CarryPrisonerToNutrientVat.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_CarryPrisonerToNutrientVat.cs
similarity index 100%
rename from Source/ArachnaeSwarm/JobDriver_CarryPrisonerToNutrientVat.cs
rename to Source/ArachnaeSwarm/Jobs/JobDriver_CarryPrisonerToNutrientVat.cs
diff --git a/Source/ArachnaeSwarm/Jobs/JobDriver_Refuel_Nutrition.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_Refuel_Nutrition.cs
new file mode 100644
index 0000000..f048094
--- /dev/null
+++ b/Source/ArachnaeSwarm/Jobs/JobDriver_Refuel_Nutrition.cs
@@ -0,0 +1,88 @@
+using System.Collections.Generic;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class JobDriver_Refuel_Nutrition : JobDriver
+ {
+ private const TargetIndex RefuelableInd = TargetIndex.A;
+ private const TargetIndex FuelInd = TargetIndex.B;
+ private const int RefuelingDuration = 240;
+
+ protected Thing Refuelable => job.GetTarget(RefuelableInd).Thing;
+
+ // --- KEY CHANGE HERE ---
+ // We specifically target CompRefuelableNutrition and its children.
+ protected CompRefuelableNutrition RefuelableComp => Refuelable.TryGetComp();
+
+ protected Thing Fuel => job.GetTarget(FuelInd).Thing;
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ if (pawn.Reserve(Refuelable, job, 1, -1, null, errorOnFailed))
+ {
+ return pawn.Reserve(Fuel, job, 1, -1, null, errorOnFailed);
+ }
+ return false;
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ this.FailOnDespawnedNullOrForbidden(RefuelableInd);
+ AddEndCondition(() => !RefuelableComp.IsFull ? JobCondition.Ongoing : JobCondition.Succeeded);
+ AddFailCondition(() => !job.playerForced && !RefuelableComp.ShouldAutoRefuelNowIgnoringFuelPct);
+ AddFailCondition(() => !RefuelableComp.allowAutoRefuel && !job.playerForced);
+
+ yield return Toils_General.DoAtomic(delegate
+ {
+ job.count = RefuelableComp.GetFuelCountToFullyRefuel();
+ });
+
+ Toil reserveFuel = Toils_Reserve.Reserve(FuelInd);
+ yield return reserveFuel;
+ yield return Toils_Goto.GotoThing(FuelInd, PathEndMode.ClosestTouch)
+ .FailOnDespawnedNullOrForbidden(FuelInd)
+ .FailOnSomeonePhysicallyInteracting(FuelInd);
+ yield return Toils_Haul.StartCarryThing(FuelInd, putRemainderInQueue: false, subtractNumTakenFromJobCount: true)
+ .FailOnDestroyedNullOrForbidden(FuelInd);
+ yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserveFuel, FuelInd, TargetIndex.None, takeFromValidStorage: true);
+ yield return Toils_Goto.GotoThing(RefuelableInd, PathEndMode.Touch);
+ yield return Toils_General.Wait(RefuelingDuration)
+ .FailOnDestroyedNullOrForbidden(FuelInd)
+ .FailOnDestroyedNullOrForbidden(RefuelableInd)
+ .FailOnCannotTouch(RefuelableInd, PathEndMode.Touch)
+ .WithProgressBarToilDelay(RefuelableInd);
+
+ // Use our custom Refuel toil for CompRefuelableNutrition
+ yield return FinalizeRefueling_Nutrition();
+ }
+
+ // Custom Finalize Toil that uses the specific Refuel method from CompRefuelableNutrition
+ public Toil FinalizeRefueling_Nutrition()
+ {
+ Toil toil = new Toil();
+ toil.initAction = delegate()
+ {
+ Pawn actor = toil.GetActor();
+ Job curJob = actor.jobs.curJob;
+ Thing refuelableThing = curJob.GetTarget(RefuelableInd).Thing;
+ CompRefuelableNutrition refuelableComp = refuelableThing.TryGetComp();
+
+ if (actor.carryTracker.CarriedThing == null)
+ {
+ Log.Error(actor + " is not carrying anything to refuel with.");
+ // The correct way to end the job from within a Toil's action.
+ actor.jobs.EndCurrentJob(JobCondition.Incompletable);
+ return;
+ }
+
+ // Call the specific Refuel method from our custom component
+ refuelableComp.Refuel(new List { actor.carryTracker.CarriedThing });
+ };
+ toil.defaultCompleteMode = ToilCompleteMode.Instant;
+ return toil;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/FloatMenuOptionProvider_SuperCarry.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/FloatMenuOptionProvider_SuperCarry.cs
similarity index 100%
rename from Source/ArachnaeSwarm/FloatMenuOptionProvider_SuperCarry.cs
rename to Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/FloatMenuOptionProvider_SuperCarry.cs
diff --git a/Source/ArachnaeSwarm/JobDriver_SuperCarry.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/JobDriver_SuperCarry.cs
similarity index 100%
rename from Source/ArachnaeSwarm/JobDriver_SuperCarry.cs
rename to Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/JobDriver_SuperCarry.cs
diff --git a/Source/ArachnaeSwarm/SuperCarryExtension.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/SuperCarryExtension.cs
similarity index 100%
rename from Source/ArachnaeSwarm/SuperCarryExtension.cs
rename to Source/ArachnaeSwarm/Jobs/JobDriver_SuperCarry/SuperCarryExtension.cs
diff --git a/Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs b/Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/Harmony_ProjectileInterceptor.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Harmony_ProjectileInterceptor.cs
rename to Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/Harmony_ProjectileInterceptor.cs
diff --git a/Source/ArachnaeSwarm/Hediff_DynamicInterceptor.cs b/Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/Hediff_DynamicInterceptor.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Hediff_DynamicInterceptor.cs
rename to Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/Hediff_DynamicInterceptor.cs
diff --git a/Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs b/Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/ThingComp_GuardianPsyField.cs
similarity index 100%
rename from Source/ArachnaeSwarm/ThingComp_GuardianPsyField.cs
rename to Source/ArachnaeSwarm/Thing_Comps/ARA_ThingComp_GuardianPsyField/ThingComp_GuardianPsyField.cs
diff --git a/Source/ArachnaeSwarm/WorkGivers/WorkGiver_Refuel_Nutrition.cs b/Source/ArachnaeSwarm/WorkGivers/WorkGiver_Refuel_Nutrition.cs
new file mode 100644
index 0000000..215efd5
--- /dev/null
+++ b/Source/ArachnaeSwarm/WorkGivers/WorkGiver_Refuel_Nutrition.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class WorkGiver_Refuel_Nutrition : WorkGiver_Scanner
+ {
+ public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial);
+
+ public override PathEndMode PathEndMode => PathEndMode.Touch;
+
+ public override IEnumerable PotentialWorkThingsGlobal(Pawn pawn)
+ {
+ // Find all buildings that have our special component.
+ return pawn.Map.listerBuildings.allBuildingsColonist.Where(b =>
+ b.GetComp() != null);
+ }
+
+ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ var building = t as Building;
+ if (building == null) return false;
+
+ // --- KEY CHANGE HERE ---
+ // Target the specific nutrition component
+ var refuelableComp = building.GetComp();
+ if (refuelableComp == null || refuelableComp.IsFull) return false;
+
+ if (!refuelableComp.ShouldAutoRefuelNow && !forced) return false;
+
+ if (building.IsForbidden(pawn) || !pawn.CanReserve(building, 1, -1, null, forced)) return false;
+
+ var fuel = FindBestFuel(pawn, refuelableComp);
+ if (fuel == null)
+ {
+ JobFailReason.Is("NoFuelToRefuel".Translate(refuelableComp.Props.fuelFilter.Summary));
+ return false;
+ }
+
+ return true;
+ }
+
+ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ var building = t as Building;
+ var refuelableComp = building.GetComp();
+ var fuel = FindBestFuel(pawn, refuelableComp);
+
+ // Return our custom Job
+ return new Job(DefDatabase.GetNamed("ARA_Refuel_Nutrition"), building, fuel);
+ }
+
+ private Thing FindBestFuel(Pawn pawn, CompRefuelable refuelable)
+ {
+ var fuelFilter = refuelable.Props.fuelFilter;
+ return GenClosest.ClosestThingReachable(
+ pawn.Position,
+ pawn.Map,
+ ThingRequest.ForGroup(ThingRequestGroup.HaulableEver),
+ PathEndMode.ClosestTouch,
+ TraverseParms.For(pawn),
+ 9999f,
+ thing => !thing.IsForbidden(pawn) && fuelFilter.Allows(thing) && pawn.CanReserve(thing)
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/CatastropheMissileSilo_Implementation_Plan.md b/Source/Documents/CatastropheMissileSilo_Implementation_Plan.md
similarity index 100%
rename from CatastropheMissileSilo_Implementation_Plan.md
rename to Source/Documents/CatastropheMissileSilo_Implementation_Plan.md
diff --git a/Railgun_System_Documentation.md b/Source/Documents/Railgun_System_Documentation.md
similarity index 100%
rename from Railgun_System_Documentation.md
rename to Source/Documents/Railgun_System_Documentation.md