diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index df51e23..300064a 100644
Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ
diff --git a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_HiveMind.xml b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_HiveMind.xml
index 58a5831..62ecf34 100644
--- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_HiveMind.xml
+++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_HiveMind.xml
@@ -4,14 +4,15 @@
ARA_HiveMindMaster
阿拉克涅女皇种是虫群意识的中心节点, 作为主脑统御整个阿拉克涅虫群。其体内拥有大量未分化的修复细胞,可以以常人无法想象的速度自行治愈所有的创伤。
- ArachnaeSwarm.Hediff_HiveMindMaster
+
+ HediffWithComps
(0.8, 0.3, 0.8)
false
false
100
-
+
0
0
@@ -28,16 +29,20 @@
-
- 3200
+
+ OverlordNode
+
ARA_HiveMindDrone
阿拉克涅督虫通过心灵与阿拉克涅女皇种相链接。如果女皇死亡,督虫也将停止生命活动。
- ArachnaeSwarm.Hediff_HiveMindDrone
+
+ HediffWithComps
(0.6, 0.4, 0.8)
false
false
@@ -45,6 +50,13 @@
0
0
+
+ ARA_ChitinArmor
+
+
+
+ 1
+ 0
Mood
Joy
@@ -61,15 +73,18 @@
-
- 6400
+
+ HiveNode
-
+
+
ARA_NonPlayer_HiveMindDroneHediff
@@ -77,6 +92,36 @@
+
+ ARA_GestaltOverseer
+
+ ArachnaeSwarm.PawnRelationWorker_GestaltOverseer
+ 185
+ false
+ 100
+ 0
+ 0
+ 0
+ 0
+ true
+ true
+ true
+ true
+
+
+ ARA_HiveMindDrone_Though
+ ThoughtWorker_Hediff
+ ARA_HiveMindDrone
+ true
+ Baby, Child, Adult
+
+
+
+ 我身体中的本能正在呼唤节点监管!
+ -99999
+
+
+
ARA_NonPlayer_HiveMindDroneHediff
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 0513947..72349a4 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
@@ -536,6 +536,8 @@
0
-3000
3000
+
+ 1
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml
index ba64f65..ef9c188 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml
@@ -468,6 +468,7 @@
ColonistLost
KnowColonistDied
+ PawnWithGoodOpinionDied
PsychicDrone
Naked
AnyBodyPartButGroinCovered_Disapproved_Female
@@ -612,6 +613,9 @@
0
+
+ 8
+ 1
@@ -779,6 +783,8 @@
这只阿拉克涅虫族的身躯是如此巨大,以至于靠近它的敌人会被直接一脚踩死
ArachnaeSwarm/UI/Abilities/ARA_Area_Crush
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
index 0b0a438..685c2a7 100644
--- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
@@ -130,4 +130,7 @@
成功将 {0} 的内脏全部翻出
目标没有可以翻出的器官
+
+ 区域伤害启动
+ 区域伤害关闭
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml
index 0b549d1..e7e5787 100644
--- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml
@@ -4,4 +4,10 @@
守护者力场
+ 蜂巢网络
+ 无节点生物
+ 监管网络负荷
+
+ 蜂巢网络是阿拉克涅虫群用于建立格式塔思维簇的体系,这使得整个族群可以在女皇种的统一指挥下获得强大的一致性。
+ 警告:蜂巢网络正在超载,这将会直接影响女皇种的心情,并有可能导致整个网络的传导性崩溃!
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 11e8567..aef75e0 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 4002f54..e99d121 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -1,22 +1,22 @@
{
"Version": 1,
- "WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
+ "WorkspaceRootPath": "D:\\SteamLibrary\\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\\abilities\\trackingcharge\\pawnflyer_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\pawnflyer_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_gestaltnode\\hediffcomp_gestaltnode.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\hediffcomp_gestaltnode.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\\abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\compabilityeffect_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_gestaltnode\\gestaltbandwidthgizmo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\gestaltbandwidthgizmo.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\\abilities\\trackingcharge\\verb_castabilitytrackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\verb_castabilitytrackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_gestaltnode\\gestaltcontrolgroup.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\gestaltcontrolgroup.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\\abilities\\trackingcharge\\compproperties_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\trackingcharge\\compproperties_trackingcharge.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_gestaltnode\\gestaltcontrolgroupgizmo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\gestaltcontrolgroupgizmo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -26,8 +26,21 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 2,
+ "SelectedChildIndex": 0,
"Children": [
+ {
+ "$type": "Document",
+ "DocumentIndex": 0,
+ "Title": "HediffComp_GestaltNode.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
+ "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAABQAAAAnAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-20T08:24:06.173Z",
+ "EditorCaption": ""
+ },
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
@@ -35,51 +48,41 @@
{
"$type": "Document",
"DocumentIndex": 2,
- "Title": "Verb_CastAbilityTrackingCharge.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
- "RelativeDocumentMoniker": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
- "RelativeToolTip": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAANAAAAAAAAAA==",
+ "Title": "GestaltControlGroup.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
+ "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:14.205Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 0,
- "Title": "PawnFlyer_TrackingCharge.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
- "RelativeDocumentMoniker": "Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
- "RelativeToolTip": "Abilities\\TrackingCharge\\PawnFlyer_TrackingCharge.cs",
- "ViewState": "AgIAAIwBAAAAAAAAAAAAAKMBAAA3AAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:13.727Z",
+ "WhenOpened": "2026-01-20T08:01:28.552Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
- "Title": "CompProperties_TrackingCharge.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
- "RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
- "RelativeToolTip": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+ "Title": "GestaltControlGroupGizmo.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
+ "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
+ "ViewState": "AgIAAEAAAAAAAAAAAAAUwCwAAABBAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:13.26Z"
+ "WhenOpened": "2026-01-20T07:59:09.365Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
- "Title": "CompAbilityEffect_TrackingCharge.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
- "RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
- "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
- "RelativeToolTip": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAABAAAAAAAAAA==",
+ "Title": "GestaltBandwidthGizmo.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
+ "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAuwBMAAAA2AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-31T03:34:12.758Z"
+ "WhenOpened": "2026-01-20T07:59:08.824Z",
+ "EditorCaption": ""
}
]
}
diff --git a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
index 7cd7218..267eaa0 100644
--- a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
+++ b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
@@ -50,4 +50,16 @@ namespace ArachnaeSwarm
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_SoundDefOf));
}
}
+
+ [DefOf]
+ public static class ARA_PawnRelationDefOf
+ {
+ public static PawnRelationDef ARA_GestaltOverseer;
+
+ static ARA_PawnRelationDefOf()
+ {
+ DefOfHelper.EnsureInitializedInCtor(typeof(ARA_PawnRelationDefOf));
+ }
+ }
+
}
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index cc4d741..8154645 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -34,6 +34,9 @@
4
+
+
+
..\..\..\..\..\..\workshop\content\294100\2009463077\1.5\Assemblies\0Harmony.dll
False
@@ -75,7 +78,6 @@
False
-
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompGestalt.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompGestalt.cs
new file mode 100644
index 0000000..5477779
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompGestalt.cs
@@ -0,0 +1,86 @@
+using System.Collections.Generic;
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompGestalt : ThingComp
+ {
+ private Pawn_GestaltTracker tracker;
+
+ public Pawn_GestaltTracker GestaltTracker
+ {
+ get
+ {
+ if (tracker == null)
+ {
+ Pawn pawn = parent as Pawn;
+ if (pawn != null && pawn.IsGestaltNode(GestaltNodeType.OverlordNode))
+ {
+ tracker = new Pawn_GestaltTracker(pawn);
+ }
+ }
+ return tracker;
+ }
+ }
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ // 初始化 tracker
+ if (GestaltTracker != null)
+ {
+ // 确保控制组数量正确
+ GestaltTracker.Notify_ControlGroupAmountChanged();
+
+ // 加载时重新连接已控制的 pawn
+ if (respawningAfterLoad)
+ {
+ ReconnectControlledPawns();
+ }
+ }
+ }
+
+ private void ReconnectControlledPawns()
+ {
+ Pawn pawn = parent as Pawn;
+ if (pawn == null) return;
+
+ // 查找所有有 GestaltOverseer 关系的 pawn
+ List relations = pawn.relations.DirectRelations;
+ foreach (DirectPawnRelation relation in relations)
+ {
+ if (relation.def == ARA_PawnRelationDefOf.ARA_GestaltOverseer)
+ {
+ Pawn hiveNode = relation.otherPawn;
+ if (hiveNode != null && hiveNode.IsGestaltNode(GestaltNodeType.HiveNode))
+ {
+ GestaltTracker?.AssignPawnToControlGroup(hiveNode);
+ }
+ }
+ }
+ }
+
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ Pawn pawn = parent as Pawn;
+ if (pawn == null || !pawn.IsGestaltNode(GestaltNodeType.OverlordNode))
+ yield break;
+
+ if (GestaltTracker == null)
+ yield break;
+
+ foreach (Gizmo gizmo in GestaltTracker.GetGizmos())
+ {
+ yield return gizmo;
+ }
+ }
+
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+ Scribe_Deep.Look(ref tracker, "gestaltTracker", parent as Pawn);
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompProperties_Gestalt.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompProperties_Gestalt.cs
new file mode 100644
index 0000000..ce5a5e9
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/CompProperties_Gestalt.cs
@@ -0,0 +1,12 @@
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_Gestalt : CompProperties
+ {
+ public CompProperties_Gestalt()
+ {
+ this.compClass = typeof(CompGestalt);
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltBandwidthGizmo.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltBandwidthGizmo.cs
new file mode 100644
index 0000000..bd312b6
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltBandwidthGizmo.cs
@@ -0,0 +1,83 @@
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.Sound;
+
+namespace ArachnaeSwarm
+{
+ public class GestaltBandwidthGizmo : Gizmo
+ {
+ private Pawn_GestaltTracker tracker;
+
+ public GestaltBandwidthGizmo(Pawn_GestaltTracker tracker)
+ {
+ this.tracker = tracker;
+ this.Order = -90f; // 放在最前面
+ }
+
+ public override bool Visible => tracker != null && tracker.Pawn != null && tracker.Pawn.IsGestaltNode(GestaltNodeType.OverlordNode);
+
+ public override float GetWidth(float maxWidth)
+ {
+ return 140f;
+ }
+
+ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
+ {
+ Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
+ Rect rect2 = rect.ContractedBy(6f);
+
+ // 背景
+ GUI.color = parms.lowLight ? Command.LowLightBgColor : Color.white;
+ GenUI.DrawTextureWithMaterial(rect, Command.BGTex, null);
+ GUI.color = Color.white;
+
+ // 标题
+ Text.Font = GameFont.Tiny;
+ Text.Anchor = TextAnchor.UpperCenter;
+ Widgets.Label(new Rect(rect2.x, rect2.y, rect2.width, 18f), "ARA_GestaltBandwidth".Translate());
+
+ // 带宽条
+ Rect barRect = new Rect(rect2.x, rect2.y + 20f, rect2.width, 20f);
+ float fillPercent = (float)tracker.UsedBandwidth / tracker.TotalBandwidth;
+ Widgets.FillableBar(barRect, fillPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.6f, 0.8f)));
+
+ // 带宽文本
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.MiddleCenter;
+ string bandwidthText = $"{tracker.UsedBandwidth}/{tracker.TotalBandwidth}";
+ Widgets.Label(barRect, bandwidthText);
+
+ // 控制组数量
+ Rect groupRect = new Rect(rect2.x, rect2.y + 45f, rect2.width, 20f);
+ Text.Font = GameFont.Tiny;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ string groupText = "ARA_GestaltGroup".Translate() + $": {tracker.ControlGroups.Count}/{tracker.TotalAvailableControlGroups}";
+ Widgets.Label(groupRect, groupText);
+
+ Text.Anchor = TextAnchor.UpperLeft;
+ Text.Font = GameFont.Small;
+
+ // 鼠标悬停提示
+ if (Mouse.IsOver(rect))
+ {
+ TooltipHandler.TipRegion(rect, () =>
+ {
+ string tip = "ARA_GestaltBandwidthTip".Translate(tracker.UsedBandwidth, tracker.TotalBandwidth);
+ tip += $"\n\n{"ARA_GestaltGroup".Translate()}: {tracker.ControlGroups.Count}/{tracker.TotalAvailableControlGroups}";
+
+ if (tracker.UsedBandwidth > tracker.TotalBandwidth)
+ {
+ tip += $"\n\n{"ARA_GestaltBandwidthExceeded".Translate()}".Colorize(Color.red);
+ }
+
+ return tip;
+ }, 7234342);
+
+ Widgets.DrawHighlight(rect);
+ }
+
+ return new GizmoResult(GizmoState.Clear);
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroup.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroup.cs
new file mode 100644
index 0000000..41887c4
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroup.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class GestaltControlGroup : IExposable
+ {
+ private List assignedPawns = new List();
+ private Pawn_GestaltTracker tracker;
+
+ public List AssignedPawns => assignedPawns;
+ public Pawn_GestaltTracker Tracker => tracker;
+ public int Index => Tracker.ControlGroups.IndexOf(this) + 1;
+
+ public GestaltControlGroup(Pawn_GestaltTracker tracker)
+ {
+ this.tracker = tracker;
+ }
+
+ public bool TryUnassign(Pawn pawn)
+ {
+ return assignedPawns.Remove(pawn);
+ }
+
+ public void Assign(Pawn pawn)
+ {
+ // 先从其他控制组移除
+ foreach (GestaltControlGroup controlGroup in tracker.ControlGroups)
+ {
+ controlGroup.TryUnassign(pawn);
+ }
+
+ assignedPawns.Add(pawn);
+
+ // 唤醒休眠的pawn
+ pawn.TryGetComp()?.WakeUp();
+ pawn.jobs?.CheckForJobOverride();
+ }
+
+ public void ExposeData()
+ {
+ Scribe_Collections.Look(ref assignedPawns, "assignedPawns", LookMode.Reference);
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
+ {
+ assignedPawns.RemoveAll((Pawn x) => x == null);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroupGizmo.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroupGizmo.cs
new file mode 100644
index 0000000..d02b73f
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltControlGroupGizmo.cs
@@ -0,0 +1,87 @@
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class GestaltControlGroupGizmo : Gizmo
+ {
+ private GestaltControlGroup controlGroup;
+
+ public override bool Visible => controlGroup.AssignedPawns.Count > 0;
+ public override float Order => -89f;
+
+ public GestaltControlGroupGizmo(GestaltControlGroup controlGroup)
+ {
+ this.controlGroup = controlGroup;
+ }
+
+ public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
+ {
+ Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
+ Rect innerRect = rect.ContractedBy(6f);
+
+ // 背景
+ GUI.color = parms.lowLight ? Command.LowLightBgColor : Color.white;
+ GenUI.DrawTextureWithMaterial(rect, Command.BGTex, null);
+ GUI.color = Color.white;
+
+ // 控制组编号
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.UpperLeft;
+ string label = "ARA_GestaltGroup".Translate();
+ Widgets.Label(innerRect, label);
+
+ // 显示被控制的pawn
+ Rect pawnRect = new Rect(innerRect.x, innerRect.y + 20f, innerRect.width, innerRect.height - 20f);
+
+ List assignedPawns = controlGroup.AssignedPawns;
+ if (assignedPawns.Count == 0)
+ {
+ GUI.color = ColoredText.SubtleGrayColor;
+ Text.Anchor = TextAnchor.MiddleCenter;
+ Widgets.Label(pawnRect, "(" + "ARA_NoGestaltPawns".Translate() + ")");
+ Text.Anchor = TextAnchor.UpperLeft;
+ GUI.color = Color.white;
+ return new GizmoResult(GizmoState.Clear);
+ }
+
+ // 计算pawn图标布局
+ float iconSize = Mathf.Min(pawnRect.width / assignedPawns.Count, pawnRect.height);
+ float spacing = (pawnRect.width - (iconSize * assignedPawns.Count)) / (assignedPawns.Count + 1);
+
+ for (int i = 0; i < assignedPawns.Count; i++)
+ {
+ Rect iconRect = new Rect(
+ pawnRect.x + spacing + (iconSize + spacing) * i,
+ pawnRect.y + (pawnRect.height - iconSize) / 2,
+ iconSize,
+ iconSize
+ );
+
+ Pawn pawn = assignedPawns[i];
+ Widgets.ThingIcon(iconRect, pawn);
+
+ if (Mouse.IsOver(iconRect))
+ {
+ Widgets.DrawHighlight(iconRect);
+ TooltipHandler.TipRegion(iconRect, pawn.LabelCap);
+
+ if (Widgets.ButtonInvisible(iconRect))
+ {
+ CameraJumper.TryJumpAndSelect(pawn);
+ }
+ }
+ }
+
+ return new GizmoResult(GizmoState.Clear);
+ }
+
+ public override float GetWidth(float maxWidth)
+ {
+ return 130f;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltUtility.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltUtility.cs
new file mode 100644
index 0000000..de1d1c0
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/GestaltUtility.cs
@@ -0,0 +1,48 @@
+using ArachnaeSwarm;
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public static class GestaltUtility
+ {
+ public static Pawn GetOverlord(this Pawn pawn)
+ {
+ List relations = pawn.relations.DirectRelations;
+ for (int i = 0; i < relations.Count; i++)
+ {
+ if (relations[i].def == ARA_PawnRelationDefOf.ARA_GestaltOverseer)
+ {
+ return relations[i].otherPawn;
+ }
+ }
+ return null;
+ }
+
+ public static Pawn_GestaltTracker GestaltTracker(this Pawn pawn)
+ {
+ HediffComp_GestaltNode comp = pawn.GetGestaltNodeComp();
+ return comp?.GestaltTracker;
+ }
+
+ public static void GetHiveNodesInAssignedOrder(Pawn overlord, ref List outHiveNodes)
+ {
+ outHiveNodes.Clear();
+ Pawn_GestaltTracker tracker = overlord.GestaltTracker();
+ if (tracker == null)
+ return;
+
+ foreach (GestaltControlGroup group in tracker.ControlGroups)
+ {
+ foreach (Pawn pawn in group.AssignedPawns)
+ {
+ if (!outHiveNodes.Contains(pawn) && pawn.IsGestaltNode(GestaltNodeType.HiveNode))
+ {
+ outHiveNodes.Add(pawn);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffCompProperties_GestaltNode.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffCompProperties_GestaltNode.cs
new file mode 100644
index 0000000..89f7de2
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffCompProperties_GestaltNode.cs
@@ -0,0 +1,14 @@
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class HediffCompProperties_GestaltNode : HediffCompProperties
+ {
+ public GestaltNodeType nodeType = GestaltNodeType.HiveNode;
+
+ public HediffCompProperties_GestaltNode()
+ {
+ this.compClass = typeof(HediffComp_GestaltNode);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffComp_GestaltNode.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffComp_GestaltNode.cs
new file mode 100644
index 0000000..7dcb654
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffComp_GestaltNode.cs
@@ -0,0 +1,221 @@
+using ArachnaeSwarm;
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+using UnityEngine;
+
+namespace ArachnaeSwarm
+{
+ public enum GestaltNodeType
+ {
+ HiveNode,
+ OverlordNode
+ }
+
+ public class HediffComp_GestaltNode : HediffComp
+ {
+ private GestaltNodeType? cachedNodeType;
+ private Pawn_GestaltTracker tracker;
+ private bool wasConnected = false; // 缓存连接状态,避免每帧都调整严重性
+
+ public GestaltNodeType NodeType
+ {
+ get
+ {
+ if (!cachedNodeType.HasValue)
+ {
+ HediffCompProperties_GestaltNode props = this.props as HediffCompProperties_GestaltNode;
+ cachedNodeType = props?.nodeType ?? GestaltNodeType.HiveNode;
+ }
+ return cachedNodeType.Value;
+ }
+ }
+
+ public Pawn_GestaltTracker GestaltTracker
+ {
+ get
+ {
+ CompGestalt comp = Pawn.TryGetComp();
+ if (comp != null)
+ {
+ return comp.GestaltTracker;
+ }
+
+ if (tracker == null && NodeType == GestaltNodeType.OverlordNode)
+ {
+ tracker = new Pawn_GestaltTracker(Pawn);
+ }
+ return tracker;
+ }
+ }
+
+ public override void CompPostMake()
+ {
+ base.CompPostMake();
+ // 初始化时根据连接状态设置严重性
+ UpdateSeverityBasedOnConnection();
+ }
+
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ base.CompPostTick(ref severityAdjustment);
+
+ if (NodeType == GestaltNodeType.HiveNode)
+ {
+ // 定期更新严重性
+ if (Find.TickManager.TicksGame % 60 == 0) // 每60tick检查一次
+ {
+ UpdateSeverityBasedOnConnection();
+ }
+
+ // 定期寻找 OverlordNode
+ if (Pawn.IsColonist &&
+ Pawn.Spawned &&
+ !Pawn.Dead &&
+ Find.TickManager.TicksGame % 250 == 0)
+ {
+ TryFindOverlord();
+ }
+ }
+ }
+
+ ///
+ /// 根据连接状态更新 Hediff 严重性
+ ///
+ public void UpdateSeverityBasedOnConnection()
+ {
+ if (NodeType != GestaltNodeType.HiveNode || parent == null)
+ return;
+
+ bool isConnected = IsConnectedToOverlord();
+
+ // 只有连接状态改变时才更新,避免每帧都设置
+ if (isConnected != wasConnected)
+ {
+ float targetSeverity = isConnected ? 1.5f : 0.5f;
+
+ // 平滑过渡到目标严重性
+ if (Mathf.Abs(parent.Severity - targetSeverity) > 0.01f)
+ {
+ parent.Severity = targetSeverity;
+ }
+
+ wasConnected = isConnected;
+
+ // 如果严重性改变,需要重新计算Pawn的能力
+ Pawn.health.Notify_HediffChanged(parent);
+ }
+ }
+
+ ///
+ /// 检查是否连接到 Overlord
+ ///
+ public bool IsConnectedToOverlord()
+ {
+ return Pawn.GetOverlord() != null;
+ }
+
+ public void TryFindOverlord()
+ {
+ // 如果已经有Overlord,更新连接状态并返回
+ if (IsConnectedToOverlord())
+ {
+ UpdateSeverityBasedOnConnection();
+ return;
+ }
+
+ // 在殖民地寻找可用的OverlordNode
+ Pawn bestOverlord = null;
+ float bestScore = -1f;
+
+ foreach (Pawn pawn in Pawn.Map.mapPawns.FreeColonists)
+ {
+ HediffComp_GestaltNode nodeComp = pawn.GetGestaltNodeComp();
+ if (nodeComp?.NodeType == GestaltNodeType.OverlordNode &&
+ pawn != Pawn &&
+ !pawn.Dead &&
+ !pawn.Downed)
+ {
+ Pawn_GestaltTracker tracker = pawn.GestaltTracker();
+ if (tracker != null && tracker.CanControlPawn(Pawn))
+ {
+ float score = CalculateOverlordScore(pawn, tracker);
+ if (score > bestScore)
+ {
+ bestScore = score;
+ bestOverlord = pawn;
+ }
+ }
+ }
+ }
+
+ // 找到合适的Overlord,建立关系并更新严重性
+ if (bestOverlord != null)
+ {
+ Pawn.relations.AddDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, bestOverlord);
+ UpdateSeverityBasedOnConnection();
+ }
+ }
+
+ private float CalculateOverlordScore(Pawn overlord, Pawn_GestaltTracker tracker)
+ {
+ float score = 0f;
+
+ if (overlord.Spawned && Pawn.Spawned && overlord.Map == Pawn.Map)
+ {
+ float distance = overlord.Position.DistanceTo(Pawn.Position);
+ score += 100f / (distance + 1f);
+ }
+
+ float availableBandwidth = tracker.TotalBandwidth - tracker.UsedBandwidth;
+ score += availableBandwidth * 10f;
+
+ score += (10 - tracker.ControlGroups.Count) * 5f;
+
+ return score;
+ }
+
+ public override void CompPostPostRemoved()
+ {
+ base.CompPostPostRemoved();
+
+ // 当Hediff被移除时,如果连接到Overlord,需要断开连接
+ if (NodeType == GestaltNodeType.HiveNode && IsConnectedToOverlord())
+ {
+ Pawn overlord = Pawn.GetOverlord();
+ if (overlord != null)
+ {
+ Pawn.relations.RemoveDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, overlord);
+ }
+ }
+ }
+
+ public override void CompExposeData()
+ {
+ base.CompExposeData();
+ Scribe_Values.Look(ref wasConnected, "wasConnected", false);
+ }
+ }
+ public static class HediffExtensions
+ {
+ public static HediffComp_GestaltNode GetGestaltNodeComp(this Pawn pawn)
+ {
+ if (pawn?.health?.hediffSet?.hediffs == null)
+ return null;
+
+ foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
+ {
+ HediffComp_GestaltNode comp = hediff.TryGetComp();
+ if (comp != null)
+ return comp;
+ }
+ return null;
+ }
+
+ public static bool IsGestaltNode(this Pawn pawn, GestaltNodeType nodeType)
+ {
+ HediffComp_GestaltNode comp = pawn.GetGestaltNodeComp();
+ return comp?.NodeType == nodeType;
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/PawnRelationWorker_GestaltOverseer.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/PawnRelationWorker_GestaltOverseer.cs
new file mode 100644
index 0000000..daf361b
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/PawnRelationWorker_GestaltOverseer.cs
@@ -0,0 +1,95 @@
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class PawnRelationWorker_GestaltOverseer : PawnRelationWorker
+ {
+ public override void OnRelationCreated(Pawn firstPawn, Pawn secondPawn)
+ {
+ base.OnRelationCreated(firstPawn, secondPawn);
+
+ // 确定谁是Overlord,谁是HiveNode
+ Pawn overlord = firstPawn.IsGestaltNode(GestaltNodeType.OverlordNode) ? firstPawn : secondPawn;
+ Pawn hiveNode = (firstPawn == overlord) ? secondPawn : firstPawn;
+
+ if (overlord.IsGestaltNode(GestaltNodeType.OverlordNode) &&
+ hiveNode.IsGestaltNode(GestaltNodeType.HiveNode))
+ {
+ Pawn_GestaltTracker tracker = overlord.GestaltTracker();
+ if (tracker != null)
+ {
+ tracker.AssignPawnToControlGroup(hiveNode);
+ }
+
+ // 更新HiveNode的严重性
+ HediffComp_GestaltNode hiveNodeComp = hiveNode.GetGestaltNodeComp();
+ if (hiveNodeComp != null)
+ {
+ hiveNodeComp.UpdateSeverityBasedOnConnection();
+ }
+ }
+ }
+
+ public override void OnRelationRemoved(Pawn firstPawn, Pawn secondPawn)
+ {
+ base.OnRelationRemoved(firstPawn, secondPawn);
+
+ // 检查是否有Overlord节点
+ Pawn overlord = null;
+ if (firstPawn.IsGestaltNode(GestaltNodeType.OverlordNode))
+ overlord = firstPawn;
+ else if (secondPawn.IsGestaltNode(GestaltNodeType.OverlordNode))
+ overlord = secondPawn;
+
+ Pawn hiveNode = (overlord == firstPawn) ? secondPawn : firstPawn;
+
+ if (overlord != null)
+ {
+ Pawn_GestaltTracker tracker = overlord.GestaltTracker();
+ if (tracker != null)
+ {
+ tracker.UnassignPawnFromAnyControlGroup(hiveNode);
+ }
+ }
+
+ // 更新HiveNode的严重性
+ HediffComp_GestaltNode hiveNodeComp = hiveNode.GetGestaltNodeComp();
+ if (hiveNodeComp != null)
+ {
+ hiveNodeComp.UpdateSeverityBasedOnConnection();
+ }
+ }
+
+ public override void Notify_PostRemovedByDeath(Pawn firstPawn, Pawn secondPawn)
+ {
+ base.Notify_PostRemovedByDeath(firstPawn, secondPawn);
+
+ // 处理死亡事件
+ Pawn overlord = (firstPawn.IsGestaltNode(GestaltNodeType.OverlordNode) ? firstPawn : secondPawn);
+ Pawn hiveNode = (firstPawn == overlord) ? secondPawn : firstPawn;
+
+ if (!hiveNode.Dead && hiveNode.IsGestaltNode(GestaltNodeType.HiveNode))
+ {
+ // 断开连接并寻找新的Overlord
+ if (overlord != null && !overlord.Dead)
+ {
+ HediffComp_GestaltNode hiveNodeComp = hiveNode.GetGestaltNodeComp();
+ if (hiveNodeComp != null)
+ {
+ hiveNodeComp.UpdateSeverityBasedOnConnection();
+ }
+
+ // HiveNode会自动尝试寻找新的Overlord
+ hiveNodeComp?.TryFindOverlord();
+ }
+ }
+
+ if (overlord != null && !overlord.Dead)
+ {
+ Messages.Message("MessageGestaltLostControl".Translate(overlord, hiveNode) + ": " + hiveNode.LabelShortCap,
+ new LookTargets(new Thing[] { overlord, hiveNode }), MessageTypeDefOf.NeutralEvent);
+ }
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/Pawn_GestaltTracker.cs b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/Pawn_GestaltTracker.cs
new file mode 100644
index 0000000..fa6af55
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/Pawn_GestaltTracker.cs
@@ -0,0 +1,194 @@
+using ArachnaeSwarm;
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm {
+ public class Pawn_GestaltTracker : IExposable
+ {
+ private Pawn pawn;
+ private List controlGroups = new List();
+ private List controlledPawns = new List();
+
+ public Pawn Pawn => pawn;
+ public List ControlGroups => controlGroups;
+ public List ControlledPawns => controlledPawns;
+
+ public int UsedBandwidth => (int)ControlledPawns.Sum(p => p.GetStatValue(StatDefOf.BandwidthCost));
+ public int TotalBandwidth => (int)pawn.GetStatValue(StatDefOf.MechBandwidth);
+ public int TotalAvailableControlGroups => (int)pawn.GetStatValue(StatDefOf.MechControlGroups);
+
+ public AcceptanceReport CanControlPawns
+ {
+ get
+ {
+ if (pawn.Downed)
+ return "GestaltControllerDowned".Translate(pawn.Named("PAWN"));
+ if (pawn.IsPrisoner)
+ return "GestaltControllerImprisoned".Translate(pawn.Named("PAWN"));
+ if (!pawn.Spawned)
+ return false;
+ if (pawn.InMentalState)
+ return "GestaltControllerMentalState".Translate(pawn.Named("PAWN"), pawn.MentalStateDef.Named("MENTALSTATE"));
+ return true;
+ }
+ }
+
+ public Pawn_GestaltTracker() { }
+
+ public Pawn_GestaltTracker(Pawn pawn)
+ {
+ this.pawn = pawn;
+ Notify_ControlGroupAmountChanged();
+ }
+
+ public bool CanControlPawn(Pawn targetPawn)
+ {
+ if (targetPawn.GetOverlord() != null)
+ return false;
+
+ float bandwidthCost = targetPawn.GetStatValue(StatDefOf.BandwidthCost);
+ return UsedBandwidth + bandwidthCost <= TotalBandwidth;
+ }
+
+ public GestaltControlGroup GetControlGroup(Pawn targetPawn)
+ {
+ foreach (GestaltControlGroup group in controlGroups)
+ {
+ if (group.AssignedPawns.Contains(targetPawn))
+ return group;
+ }
+ return null;
+ }
+
+ public void AssignPawnToControlGroup(Pawn targetPawn)
+ {
+ if (controlGroups.Count == 0)
+ {
+ Notify_ControlGroupAmountChanged();
+ if (controlGroups.Count == 0)
+ {
+ Log.Warning("Wants to assign pawn to a control group, but there are none!");
+ return;
+ }
+ }
+
+ // 分配到第一个可用的控制组
+ controlGroups[0].Assign(targetPawn);
+ Notify_BandwidthChanged();
+ }
+
+ public void UnassignPawnFromAnyControlGroup(Pawn targetPawn)
+ {
+ foreach (GestaltControlGroup group in controlGroups)
+ {
+ group.TryUnassign(targetPawn);
+ }
+ }
+
+ public void Notify_ControlGroupAmountChanged()
+ {
+ int availableGroups = TotalAvailableControlGroups;
+
+ // 添加缺少的控制组
+ while (controlGroups.Count < availableGroups)
+ {
+ controlGroups.Add(new GestaltControlGroup(this));
+ }
+
+ // 移除多余的控制组
+ while (controlGroups.Count > availableGroups)
+ {
+ GestaltControlGroup groupToRemove = controlGroups[controlGroups.Count - 1];
+
+ if (!groupToRemove.AssignedPawns.NullOrEmpty())
+ {
+ // 将pawn重新分配到其他组
+ foreach (Pawn pawn in groupToRemove.AssignedPawns)
+ {
+ if (controlGroups.Count > 1)
+ {
+ controlGroups[0].Assign(pawn);
+ }
+ }
+ }
+
+ controlGroups.RemoveAt(controlGroups.Count - 1);
+ }
+ }
+
+ public void Notify_BandwidthChanged()
+ {
+ controlledPawns.Clear();
+
+ // 收集所有被控制的pawn
+ foreach (GestaltControlGroup group in controlGroups)
+ {
+ controlledPawns.AddRange(group.AssignedPawns.Where(p => !controlledPawns.Contains(p)));
+ }
+
+ // 检查带宽限制,移除超出带宽的pawn
+ List toRemove = new List();
+ float currentBandwidth = 0f;
+
+ foreach (Pawn controlledPawn in controlledPawns)
+ {
+ float cost = controlledPawn.GetStatValue(StatDefOf.BandwidthCost);
+ if (currentBandwidth + cost <= TotalBandwidth)
+ {
+ currentBandwidth += cost;
+ }
+ else
+ {
+ toRemove.Add(controlledPawn);
+ }
+ }
+
+ foreach (Pawn pawnToRemove in toRemove)
+ {
+ UnassignPawnFromAnyControlGroup(pawnToRemove);
+ pawnToRemove.relations.RemoveDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, this.pawn);
+ }
+ }
+
+ public void Notify_ApparelChanged()
+ {
+ Notify_BandwidthChanged();
+ Notify_ControlGroupAmountChanged();
+ }
+
+ public void Notify_HediffStateChange(Hediff hediff)
+ {
+ if (hediff != null)
+ {
+ Notify_BandwidthChanged();
+ Notify_ControlGroupAmountChanged();
+ }
+ }
+
+ public IEnumerable GetGizmos()
+ {
+ yield return new GestaltBandwidthGizmo(this);
+
+ foreach (GestaltControlGroup group in controlGroups)
+ {
+ yield return new GestaltControlGroupGizmo(group);
+ }
+ }
+
+ public void ExposeData()
+ {
+ Scribe_Collections.Look(ref controlGroups, "controlGroups", LookMode.Deep, this);
+ Scribe_Collections.Look(ref controlledPawns, "controlledPawns", LookMode.Reference);
+
+ if (Scribe.mode == LoadSaveMode.PostLoadInit)
+ {
+ controlledPawns?.RemoveAll(x => x == null);
+ if (controlGroups == null)
+ controlGroups = new List();
+ }
+ }
+ }
+}
\ No newline at end of file