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