This commit is contained in:
2026-01-20 17:34:50 +08:00
parent d006386af6
commit 6c6ed9539d
20 changed files with 1023 additions and 53 deletions

Binary file not shown.

View File

@@ -4,14 +4,15 @@
<defName>ARA_HiveMindMaster</defName> <defName>ARA_HiveMindMaster</defName>
<label>阿拉克涅女皇种</label> <label>阿拉克涅女皇种</label>
<description>阿拉克涅女皇种是虫群意识的中心节点, 作为主脑统御整个阿拉克涅虫群。其体内拥有大量未分化的修复细胞,可以以常人无法想象的速度自行治愈所有的创伤。</description> <description>阿拉克涅女皇种是虫群意识的中心节点, 作为主脑统御整个阿拉克涅虫群。其体内拥有大量未分化的修复细胞,可以以常人无法想象的速度自行治愈所有的创伤。</description>
<hediffClass>ArachnaeSwarm.Hediff_HiveMindMaster</hediffClass> <!-- <hediffClass>ArachnaeSwarm.Hediff_HiveMindMaster</hediffClass> -->
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.8, 0.3, 0.8)</defaultLabelColor> <defaultLabelColor>(0.8, 0.3, 0.8)</defaultLabelColor>
<isBad>false</isBad> <isBad>false</isBad>
<scenarioCanAdd>false</scenarioCanAdd> <scenarioCanAdd>false</scenarioCanAdd>
<maxSeverity>100</maxSeverity> <maxSeverity>100</maxSeverity>
<stages> <stages>
<li> <li>
<label>连接至 {0} 个虫群工蜂</label> <!-- <label>连接至 {0} 个虫群工蜂</label> -->
<minSeverity>0</minSeverity> <minSeverity>0</minSeverity>
<foodPoisoningChanceFactor>0</foodPoisoningChanceFactor> <foodPoisoningChanceFactor>0</foodPoisoningChanceFactor>
<!-- Stat offsets will be added here later --> <!-- Stat offsets will be added here later -->
@@ -28,16 +29,20 @@
</li> </li>
</stages> </stages>
<comps> <comps>
<li Class="ArachnaeSwarm.HediffCompProperties_HiveMindMaster"> <li Class="ArachnaeSwarm.HediffCompProperties_GestaltNode">
<scanIntervalTicks>3200</scanIntervalTicks> <nodeType>OverlordNode</nodeType>
</li> </li>
<!-- <li Class="ArachnaeSwarm.HediffCompProperties_HiveMindMaster">
<scanIntervalTicks>3200</scanIntervalTicks>
</li> -->
</comps> </comps>
</HediffDef> </HediffDef>
<HediffDef> <HediffDef>
<defName>ARA_HiveMindDrone</defName> <defName>ARA_HiveMindDrone</defName>
<label>阿拉克涅督虫</label> <label>阿拉克涅督虫</label>
<description>阿拉克涅督虫通过心灵与阿拉克涅女皇种相链接。如果女皇死亡,督虫也将停止生命活动。</description> <description>阿拉克涅督虫通过心灵与阿拉克涅女皇种相链接。如果女皇死亡,督虫也将停止生命活动。</description>
<hediffClass>ArachnaeSwarm.Hediff_HiveMindDrone</hediffClass> <!-- <hediffClass>ArachnaeSwarm.Hediff_HiveMindDrone</hediffClass> -->
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor> <defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad> <isBad>false</isBad>
<scenarioCanAdd>false</scenarioCanAdd> <scenarioCanAdd>false</scenarioCanAdd>
@@ -45,6 +50,13 @@
<li> <li>
<minSeverity>0</minSeverity> <minSeverity>0</minSeverity>
<foodPoisoningChanceFactor>0</foodPoisoningChanceFactor> <foodPoisoningChanceFactor>0</foodPoisoningChanceFactor>
<enablesNeeds>
<li>ARA_ChitinArmor</li>
</enablesNeeds>
</li>
<li>
<minSeverity>1</minSeverity>
<foodPoisoningChanceFactor>0</foodPoisoningChanceFactor>
<disablesNeeds> <disablesNeeds>
<li>Mood</li> <li>Mood</li>
<li>Joy</li> <li>Joy</li>
@@ -61,15 +73,18 @@
</li> </li>
</stages> </stages>
<comps> <comps>
<li Class="ArachnaeSwarm.HediffCompProperties_HiveMindDrone"> <li Class="ArachnaeSwarm.HediffCompProperties_GestaltNode">
<unlinkedDieDelayTicks>6400</unlinkedDieDelayTicks> <!-- Default to 30 seconds --> <nodeType>HiveNode</nodeType>
</li> </li>
<li Class="HediffCompProperties_MessageAfterTicks"> <!-- <li Class="ArachnaeSwarm.HediffCompProperties_HiveMindDrone">
<unlinkedDieDelayTicks>6400</unlinkedDieDelayTicks>
</li> -->
<!-- <li Class="HediffCompProperties_MessageAfterTicks">
<ticks>1</ticks> <ticks>1</ticks>
<letterLabel>{0_labelShort} 诞生</letterLabel> <letterLabel>{0_labelShort} 诞生</letterLabel>
<letterText>一只新的阿拉克涅督虫 {0_labelShort} 已经破茧而出!她正在四处徘徊,等待女皇种的指示——使用阿拉克涅女皇种的信息素标记技能完成链接,或者等待其自行建立链接。</letterText> <letterText>一只新的阿拉克涅督虫 {0_labelShort} 已经破茧而出!她正在四处徘徊,等待女皇种的指示——使用阿拉克涅女皇种的信息素标记技能完成链接,或者等待其自行建立链接。</letterText>
<letterType>HumanPregnancy</letterType> <letterType>HumanPregnancy</letterType>
</li> </li> -->
<li Class="HediffCompProperties_RemoveIfOtherHediff"> <li Class="HediffCompProperties_RemoveIfOtherHediff">
<hediffs> <hediffs>
<li>ARA_NonPlayer_HiveMindDroneHediff</li> <li>ARA_NonPlayer_HiveMindDroneHediff</li>
@@ -77,6 +92,36 @@
</li> </li>
</comps> </comps>
</HediffDef> </HediffDef>
<PawnRelationDef>
<defName>ARA_GestaltOverseer</defName>
<label>节点监管</label>
<workerClass>ArachnaeSwarm.PawnRelationWorker_GestaltOverseer</workerClass>
<importance>185</importance>
<implied>false</implied>
<opinionOffset>100</opinionOffset>
<generationChanceFactor>0</generationChanceFactor>
<romanceChanceFactor>0</romanceChanceFactor>
<incestOpinionOffset>0</incestOpinionOffset>
<inbredChanceOnChild>0</inbredChanceOnChild>
<familyByBloodRelation>true</familyByBloodRelation>
<removeOnDeath>true</removeOnDeath>
<removeOnLeftBehind>true</removeOnLeftBehind>
<reflexive>true</reflexive>
</PawnRelationDef>
<ThoughtDef>
<defName>ARA_HiveMindDrone_Though</defName>
<workerClass>ThoughtWorker_Hediff</workerClass>
<hediff>ARA_HiveMindDrone</hediff>
<validWhileDespawned>true</validWhileDespawned>
<developmentalStageFilter>Baby, Child, Adult</developmentalStageFilter>
<stages>
<li>
<label>失联恐惧</label>
<description>我身体中的本能正在呼唤节点监管!</description>
<baseMoodEffect>-99999</baseMoodEffect>
</li>
</stages>
</ThoughtDef>
<HediffDef> <HediffDef>
<defName>ARA_NonPlayer_HiveMindDroneHediff</defName> <defName>ARA_NonPlayer_HiveMindDroneHediff</defName>
<label>野性虫群</label> <label>野性虫群</label>

View File

@@ -536,6 +536,8 @@
<ForagedNutritionPerDay>0</ForagedNutritionPerDay> <ForagedNutritionPerDay>0</ForagedNutritionPerDay>
<ComfyTemperatureMin>-3000</ComfyTemperatureMin> <ComfyTemperatureMin>-3000</ComfyTemperatureMin>
<ComfyTemperatureMax>3000</ComfyTemperatureMax> <ComfyTemperatureMax>3000</ComfyTemperatureMax>
<BandwidthCost>1</BandwidthCost>
</statBases> </statBases>
<race> <race>

View File

@@ -468,6 +468,7 @@
<cannotReceiveThoughts> <cannotReceiveThoughts>
<li>ColonistLost</li> <li>ColonistLost</li>
<li>KnowColonistDied</li> <li>KnowColonistDied</li>
<li>PawnWithGoodOpinionDied</li>
<li>PsychicDrone</li> <li>PsychicDrone</li>
<li>Naked</li> <li>Naked</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Female</li> <li>AnyBodyPartButGroinCovered_Disapproved_Female</li>
@@ -612,6 +613,9 @@
<!-- 在野外采集的营养 --> <!-- 在野外采集的营养 -->
<ForagedNutritionPerDay>0</ForagedNutritionPerDay> <ForagedNutritionPerDay>0</ForagedNutritionPerDay>
<MechBandwidth>8</MechBandwidth>
<MechControlGroups>1</MechControlGroups>
</statBases> </statBases>
<race> <race>
@@ -779,6 +783,8 @@
<toggleDescription>这只阿拉克涅虫族的身躯是如此巨大,以至于靠近它的敌人会被直接一脚踩死</toggleDescription> <toggleDescription>这只阿拉克涅虫族的身躯是如此巨大,以至于靠近它的敌人会被直接一脚踩死</toggleDescription>
<toggleIconPath>ArachnaeSwarm/UI/Abilities/ARA_Area_Crush</toggleIconPath> <toggleIconPath>ArachnaeSwarm/UI/Abilities/ARA_Area_Crush</toggleIconPath>
</li> </li>
<!-- 添加 Gestalt 组件 -->
<li Class="ArachnaeSwarm.CompProperties_Gestalt" />
</comps> </comps>
</AlienRace.ThingDef_AlienRace> </AlienRace.ThingDef_AlienRace>
</Defs> </Defs>

View File

@@ -130,4 +130,7 @@
<ARA_EjectedOrgans>成功将 {0} 的内脏全部翻出</ARA_EjectedOrgans> <ARA_EjectedOrgans>成功将 {0} 的内脏全部翻出</ARA_EjectedOrgans>
<ARA_NoEjectableOrgans>目标没有可以翻出的器官</ARA_NoEjectableOrgans> <ARA_NoEjectableOrgans>目标没有可以翻出的器官</ARA_NoEjectableOrgans>
<AreaDamageEnabled>区域伤害启动</AreaDamageEnabled>
<AreaDamageDisabled>区域伤害关闭</AreaDamageDisabled>
</LanguageData> </LanguageData>

View File

@@ -4,4 +4,10 @@
<!-- Guardian Psy-Field Gizmo --> <!-- Guardian Psy-Field Gizmo -->
<ARA_GuardianFieldGizmoLabel>守护者力场</ARA_GuardianFieldGizmoLabel> <ARA_GuardianFieldGizmoLabel>守护者力场</ARA_GuardianFieldGizmoLabel>
<ARA_GestaltGroup>蜂巢网络</ARA_GestaltGroup>
<ARA_NoGestaltPawns>无节点生物</ARA_NoGestaltPawns>
<ARA_GestaltBandwidth>监管网络负荷</ARA_GestaltBandwidth>
<ARA_GestaltBandwidthTip>蜂巢网络是阿拉克涅虫群用于建立格式塔思维簇的体系,这使得整个族群可以在女皇种的统一指挥下获得强大的一致性。</ARA_GestaltBandwidthTip>
<ARA_GestaltBandwidthExceeded>警告:蜂巢网络正在超载,这将会直接影响女皇种的心情,并有可能导致整个网络的传导性崩溃!</ARA_GestaltBandwidthExceeded>
</LanguageData> </LanguageData>

View File

@@ -1,22 +1,22 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [ "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}", "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:abilities\\trackingcharge\\pawnflyer_trackingcharge.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}", "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:abilities\\trackingcharge\\compabilityeffect_trackingcharge.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}", "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:abilities\\trackingcharge\\verb_castabilitytrackingcharge.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}", "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:abilities\\trackingcharge\\compproperties_trackingcharge.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": [ "DocumentGroupContainers": [
@@ -26,8 +26,21 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 2, "SelectedChildIndex": 0,
"Children": [ "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", "$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
@@ -35,51 +48,41 @@
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 2, "DocumentIndex": 2,
"Title": "Verb_CastAbilityTrackingCharge.cs", "Title": "GestaltControlGroup.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs", "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs", "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
"RelativeToolTip": "Abilities\\TrackingCharge\\Verb_CastAbilityTrackingCharge.cs", "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltControlGroup.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAANAAAAAAAAAA==", "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-31T03:34:14.205Z" "WhenOpened": "2026-01-20T08:01:28.552Z",
},
{
"$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",
"EditorCaption": "" "EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 3, "DocumentIndex": 3,
"Title": "CompProperties_TrackingCharge.cs", "Title": "GestaltControlGroupGizmo.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs", "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs", "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
"RelativeToolTip": "Abilities\\TrackingCharge\\CompProperties_TrackingCharge.cs", "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltControlGroupGizmo.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "ViewState": "AgIAAEAAAAAAAAAAAAAUwCwAAABBAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-31T03:34:13.26Z" "WhenOpened": "2026-01-20T07:59:09.365Z",
"EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 1, "DocumentIndex": 1,
"Title": "CompAbilityEffect_TrackingCharge.cs", "Title": "GestaltBandwidthGizmo.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
"RelativeDocumentMoniker": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs", "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs", "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
"RelativeToolTip": "Abilities\\TrackingCharge\\CompAbilityEffect_TrackingCharge.cs", "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\GestaltBandwidthGizmo.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAABAAAAAAAAAA==", "ViewState": "AgIAAAAAAAAAAAAAAAAuwBMAAAA2AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-31T03:34:12.758Z" "WhenOpened": "2026-01-20T07:59:08.824Z",
"EditorCaption": ""
} }
] ]
} }

View File

@@ -50,4 +50,16 @@ namespace ArachnaeSwarm
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_SoundDefOf)); DefOfHelper.EnsureInitializedInCtor(typeof(ARA_SoundDefOf));
} }
} }
[DefOf]
public static class ARA_PawnRelationDefOf
{
public static PawnRelationDef ARA_GestaltOverseer;
static ARA_PawnRelationDefOf()
{
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_PawnRelationDefOf));
}
}
} }

View File

@@ -34,6 +34,9 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Hediffs\ARA_GestaltNode\CompGestalt.cs" />
<Compile Include="Hediffs\ARA_GestaltNode\CompProperties_Gestalt.cs" />
<Compile Include="Hediffs\ARA_GestaltNode\GestaltBandwidthGizmo.cs" />
<Reference Include="0Harmony"> <Reference Include="0Harmony">
<HintPath>..\..\..\..\..\..\workshop\content\294100\2009463077\1.5\Assemblies\0Harmony.dll</HintPath> <HintPath>..\..\..\..\..\..\workshop\content\294100\2009463077\1.5\Assemblies\0Harmony.dll</HintPath>
<Private>False</Private> <Private>False</Private>
@@ -75,7 +78,6 @@
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Compile Include="**\*.cs" Exclude="bin\**;obj\**" /> <Compile Include="**\*.cs" Exclude="bin\**;obj\**" />
<Folder Include="FacialAnimation\" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 自定义清理任务删除obj文件夹中的临时文件 --> <!-- 自定义清理任务删除obj文件夹中的临时文件 -->

View File

@@ -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<DirectPawnRelation> 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<Gizmo> 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);
}
}
}

View File

@@ -0,0 +1,12 @@
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_Gestalt : CompProperties
{
public CompProperties_Gestalt()
{
this.compClass = typeof(CompGestalt);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class GestaltControlGroup : IExposable
{
private List<Pawn> assignedPawns = new List<Pawn>();
private Pawn_GestaltTracker tracker;
public List<Pawn> 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<CompCanBeDormant>()?.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);
}
}
}
}

View File

@@ -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<Pawn> 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;
}
}
}

View File

@@ -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<DirectPawnRelation> 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<Pawn> 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);
}
}
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<CompGestalt>();
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();
}
}
}
/// <summary>
/// 根据连接状态更新 Hediff 严重性
/// </summary>
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);
}
}
/// <summary>
/// 检查是否连接到 Overlord
/// </summary>
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<HediffComp_GestaltNode>();
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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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<GestaltControlGroup> controlGroups = new List<GestaltControlGroup>();
private List<Pawn> controlledPawns = new List<Pawn>();
public Pawn Pawn => pawn;
public List<GestaltControlGroup> ControlGroups => controlGroups;
public List<Pawn> 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<Pawn> toRemove = new List<Pawn>();
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<Gizmo> 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<GestaltControlGroup>();
}
}
}
}