This commit is contained in:
2026-01-28 11:17:26 +08:00
parent c7098a07c0
commit ae529319a9
12 changed files with 995 additions and 675 deletions

Binary file not shown.

View File

@@ -50,6 +50,7 @@
<race> <race>
<body>BeetleLikeWithClaw</body> <body>BeetleLikeWithClaw</body>
<thinkTreeMain>ARA_Insect_WithPlanting</thinkTreeMain> <thinkTreeMain>ARA_Insect_WithPlanting</thinkTreeMain>
<thinkTreeConstant>ARA_Insect_Thinktree_Constant</thinkTreeConstant>
<foodType>CarnivoreAnimal,OvivoreAnimal</foodType> <foodType>CarnivoreAnimal,OvivoreAnimal</foodType>
<baseHungerRate>0.1</baseHungerRate> <baseHungerRate>0.1</baseHungerRate>
<baseBodySize>0.5</baseBodySize> <baseBodySize>0.5</baseBodySize>

View File

@@ -757,6 +757,36 @@
</thinkRoot> </thinkRoot>
</ThinkTreeDef> </ThinkTreeDef>
<ThinkTreeDef>
<defName>ARA_Insect_Thinktree_Constant</defName>
<thinkRoot Class="ThinkNode_Priority">
<subNodes>
<!-- Despawned -->
<li Class="ThinkNode_Subtree">
<treeDef>Despawned</treeDef>
</li>
<li Class="ThinkNode_ConditionalCanDoConstantThinkTreeJobNow">
<subNodes>
<!-- Flee explosion -->
<li Class="JobGiver_FleePotentialExplosion" />
<!-- Avoid vacuums -->
<li Class="JobGiver_FindOxygen" />
<!-- Board/leave gravship -->
<li Class="JobGiver_BoardOrLeaveGravship" />
<!-- Join auto joinable caravan -->
<li Class="ThinkNode_Subtree">
<treeDef>JoinAutoJoinableCaravan</treeDef>
</li>
</subNodes>
</li>
</subNodes>
</thinkRoot>
</ThinkTreeDef>
<ThinkTreeDef> <ThinkTreeDef>
<defName>ARA_Insect_Larva_Thinktree</defName> <defName>ARA_Insect_Larva_Thinktree</defName>
<thinkRoot Class="ThinkNode_Priority"> <thinkRoot Class="ThinkNode_Priority">

View File

@@ -1,92 +1,7 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\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|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\building_ootheca.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\\building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comprefuelablenutrition.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\\building_comps\\ara_productstorage\\compproperties_productstorage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_productstorage\\compproperties_productstorage.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\\building_comps\\ara_compinteractiveproducer\\compinteractiveproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_compinteractiveproducer\\compinteractiveproducer.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\\abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_transformcorpse.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\\jobs\\jobdriver_followproducer\\thinknode_conditionalnotproducedbymechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_followproducer\\thinknode_conditionalnotproducedbymechcarrier.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\\buildings\\building_ootheca\\gizmo_pawnprogressbar.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_pawnprogressbar.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\\buildings\\building_ootheca\\gizmo_neutronflux.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_neutronflux.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_configurablemutant\\necrotictransformationutility.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_configurablemutant\\necrotictransformationutility.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\\pawn_comps\\ara_nodeswarmlifetime\\compnodeswarmlifetime.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_nodeswarmlifetime\\compnodeswarmlifetime.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\\buildings\\building_ootheca\\gizmo_queuedincubationprogress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_queuedincubationprogress.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\\buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\building_equipmentootheca.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\\buildings\\building_corpsevat\\building_corpsevat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_corpsevat\\building_corpsevat.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\\buildings\\building_corpsevat\\corpsevatextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_corpsevat\\corpsevatextension.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\\jobs\\jobdriver_plant\\jobgiver_grower.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_plant\\jobgiver_grower.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\\jobs\\jobdriver_clean\\jobgiver_cleaner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_clean\\jobgiver_cleaner.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\\abilities\\ara_huggingface\\hediff_possession.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_huggingface\\hediff_possession.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\\abilities\\ara_huggingface\\compabilityeffect_possess.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_huggingface\\compabilityeffect_possess.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\\building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.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_hediffterrainspawn\\compproperties_hediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffterrainspawn\\compproperties_hediffterrainspawn.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_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {
"Orientation": 0, "Orientation": 0,
@@ -94,271 +9,11 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 6, "SelectedChildIndex": -1,
"Children": [ "Children": [
{ {
"$type": "Bookmark", "$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CompRefuelableNutrition.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeDocumentMoniker": "Building_Comps\\CompRefuelableNutrition.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeToolTip": "Building_Comps\\CompRefuelableNutrition.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAyAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:40.77Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "CompProperties_ProductStorage.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"RelativeToolTip": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAABKAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:33.86Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "CompInteractiveProducer.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"RelativeToolTip": "Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"ViewState": "AgIAAFICAAAAAAAAAAAAAFICAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:32.573Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "CompAbilityEffect_TransformCorpse.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeToolTip": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ViewState": "AgIAAFQAAAAAAAAAAAAuwGkAAABdAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:29.604Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "ThinkNode_ConditionalNotProducedByMechCarrier.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
"RelativeToolTip": "Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABQAAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T00:51:15.459Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Building_Ootheca.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ViewState": "AgIAABwCAAAAAAAAAAAvwDICAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:31:14.555Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "NecroticTransformationUtility.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"RelativeToolTip": "Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"ViewState": "AgIAAA8AAAAAAAAAAAAtwCIAAAAcAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:44:42.184Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "CompNodeSwarmLifetime.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"ViewState": "AgIAADYAAAAAAAAAAAAtwEoAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:44:35.266Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "Gizmo_QueuedIncubationProgress.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:11:04.23Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "Gizmo_PawnProgressBar.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAAAFAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:12:03.772Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "Gizmo_NeutronFlux.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAAiAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:11:53.324Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "Building_EquipmentOotheca.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ViewState": "AgIAAEIBAAAAAAAAAAAAAEMBAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T07:52:41.869Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "Building_CorpseVat.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
"RelativeDocumentMoniker": "Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
"RelativeToolTip": "Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAgAAAASAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T10:24:46.264Z"
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "JobGiver_Grower.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"RelativeToolTip": "Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"ViewState": "AgIAAFMAAAAAAAAAAAAQwGkAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:51:03.439Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "Hediff_Possession.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"RelativeToolTip": "Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:50:05.221Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "CompAbilityEffect_Possess.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"RelativeToolTip": "Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"ViewState": "AgIAAHcAAAAAAAAAAAAAAIkAAAA5AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:50:01.549Z"
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "CorpseVatExtension.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
"RelativeDocumentMoniker": "Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
"RelativeToolTip": "Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
"ViewState": "AgIAAAAAAAAAAAAAAADwvx0AAAAoAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T10:25:01.777Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "CompDelayedTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeToolTip": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ViewState": "AgIAAFEAAAAAAAAAAAAAAF8AAAA+AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:46:06.784Z"
},
{
"$type": "Document",
"DocumentIndex": 19,
"Title": "CompProperties_HediffTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"RelativeToolTip": "Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"ViewState": "AgIAAAUAAAAAAAAAAAAtwBkAAAAxAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:44:14.682Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "JobGiver_Cleaner.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"RelativeToolTip": "Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAABwAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:51:58.899Z"
},
{
"$type": "Document",
"DocumentIndex": 20,
"Title": "CompHediffTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"RelativeToolTip": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"ViewState": "AgIAAKIAAAAAAAAAAAAawLQAAAAMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:44:10.075Z"
} }
] ]
} }

View File

@@ -334,6 +334,7 @@
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProducedByMechCarrier.cs" /> <Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProducedByMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" /> <Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_ProducedByMechCarrier.cs" /> <Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_ProducedByMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\IBidirectionalValidator.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\PawnProductionEntry.cs" /> <Compile Include="Pawn_Comps\ARA_AutoMechCarrier\PawnProductionEntry.cs" />
<Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompHediffGiver.cs" /> <Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompHediffGiver.cs" />
<Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompProperties_HediffGiver.cs" /> <Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompProperties_HediffGiver.cs" />

View File

@@ -561,20 +561,30 @@ namespace ArachnaeSwarm
} }
public override IEnumerable<Gizmo> GetGizmos() public override IEnumerable<Gizmo> GetGizmos()
{ {
base.GetGizmos(); foreach (var gizmo in base.GetGizmos())
{
if (gizmo is Command_Action cmd && cmd.defaultLabel != null)
{
string label = cmd.defaultLabel.ToString();
if (label.Contains("拆除") || label.Contains("Deconstruct") || label.Contains("半径") || label.Contains("Radius"))
continue;
}
// 强制将基础组件(如 Refuelable甚至默认排序为 -100 的东西移到后面
if (gizmo.Order >= -100f && gizmo.Order <= 0f)
{
gizmo.Order = -90f;
}
yield return gizmo;
}
// 首先获取选中的同类建筑 // 首先获取选中的同类建筑
var selectedOothecas = GetSelectedOothecas(); var selectedOothecas = GetSelectedOothecas();
bool isMultiSelect = selectedOothecas.Count > 1; bool isMultiSelect = selectedOothecas.Count > 1;
if (Faction == Faction.OfPlayer) if (Faction == Faction.OfPlayer)
{ {
// 在多选时,只在第一个建筑上显示进度条和通量条
if (!isMultiSelect || (isMultiSelect && selectedOothecas.First() == this))
{
yield return new Gizmo_PawnProgressBar(this);
yield return new Gizmo_NeutronFlux(this);
}
var config = IncubatorData?.SelectedConfig; var config = IncubatorData?.SelectedConfig;
// 添加订单按钮(多选时合并) // 添加订单按钮(多选时合并)
@@ -657,6 +667,7 @@ namespace ArachnaeSwarm
} }
} }
} }
/// <summary> /// <summary>
/// 为多选建筑显示订单菜单 /// 为多选建筑显示订单菜单
/// </summary> /// </summary>

View File

@@ -1,4 +1,6 @@
using RimWorld; using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse; using Verse;
using Verse.AI; using Verse.AI;
@@ -14,6 +16,12 @@ namespace ArachnaeSwarm
// 是否仅防御征召状态的生产者针对pawn类型生产者 // 是否仅防御征召状态的生产者针对pawn类型生产者
public bool onlyDefendDrafted = true; public bool onlyDefendDrafted = true;
// 是否排除休眠的机械族
public bool excludeDormantMechs = true;
// 是否将炮塔纳入考虑
public bool includeHostileTurrets = true;
protected override Pawn GetDefendee(Pawn pawn) protected override Pawn GetDefendee(Pawn pawn)
{ {
// 我们不需要返回Pawn类型的防御者因为我们实际上防御的是Thing // 我们不需要返回Pawn类型的防御者因为我们实际上防御的是Thing
@@ -21,18 +29,18 @@ namespace ArachnaeSwarm
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>(); CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producerComp == null || !producerComp.HasValidProducer) if (producerComp == null || !producerComp.HasValidProducer)
return null; return null;
Thing producer = producerComp.Producer; Thing producer = producerComp.Producer;
// 对于Pawn类型生产者检查是否需要征召状态 // 对于Pawn类型生产者检查是否需要征召状态
if (producer is Pawn pawnProducer) if (producer is Pawn pawnProducer)
{ {
if (onlyDefendDrafted && !pawnProducer.Drafted) if (onlyDefendDrafted && !pawnProducer.Drafted)
return null; return null;
return pawnProducer; return pawnProducer;
} }
return null; return null;
} }
@@ -42,44 +50,44 @@ namespace ArachnaeSwarm
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>(); CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producerComp == null || !producerComp.HasValidProducer) if (producerComp == null || !producerComp.HasValidProducer)
return defendRadius; return defendRadius;
// 如果生产者是建筑,使用扩展防御半径 // 如果生产者是建筑,使用扩展防御半径
if (producerComp.Producer is Building) if (producerComp.Producer is Building)
return extendedDefendRadius; return extendedDefendRadius;
return defendRadius; return defendRadius;
} }
// 重写以支持非Pawn生产者 // 重写以支持非Pawn生产者
protected override Job TryGiveJob(Pawn pawn) protected override Job TryGiveJob(Pawn pawn)
{ {
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>(); CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producerComp == null || !producerComp.HasValidProducer) if (producerComp == null || !producerComp.HasValidProducer)
return null; return null;
Thing producer = producerComp.Producer; Thing producer = producerComp.Producer;
if (producer == null || producer.Destroyed) if (producer == null || producer.Destroyed)
return null; return null;
// 对于Pawn类型生产者检查是否需要征召状态 // 对于Pawn类型生产者检查是否需要征召状态
if (producer is Pawn pawnProducer && onlyDefendDrafted) if (producer is Pawn pawnProducer && onlyDefendDrafted)
{ {
if (!pawnProducer.Drafted) if (!pawnProducer.Drafted)
return null; return null;
} }
// 如果生产者在战斗中让pawn参与防御 // 如果生产者在战斗中让pawn参与防御
if (producer is Pawn pawnProducer2 && pawnProducer2.InAggroMentalState) if (producer is Pawn pawnProducer2 && pawnProducer2.InAggroMentalState)
{ {
// 使用基类逻辑来防御Pawn类型生产者 // 使用基类逻辑来防御Pawn类型生产者
return base.TryGiveJob(pawn); return base.TryGiveJob(pawn);
} }
// 对于非Pawn生产者或非战斗状态检查是否需要防御 // 对于非Pawn生产者或非战斗状态检查是否需要防御
float defendRadiusValue = GetFlagRadius(pawn); float defendRadiusValue = GetFlagRadius(pawn);
// 寻找附近的威胁 // 寻找附近的威胁
Pawn enemy = FindEnemy(pawn, defendRadiusValue); Thing enemy = FindEnemy(pawn, defendRadiusValue);
if (enemy != null) if (enemy != null)
{ {
// 创建攻击工作 // 创建攻击工作
@@ -90,23 +98,24 @@ namespace ArachnaeSwarm
job.expireRequiresEnemiesNearby = true; job.expireRequiresEnemiesNearby = true;
return job; return job;
} }
return null; return null;
} }
private Pawn FindEnemy(Pawn pawn, float radius)
protected virtual Thing FindEnemy(Pawn pawn, float radius)
{ {
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>(); CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producerComp == null || !producerComp.HasValidProducer) if (producerComp == null || !producerComp.HasValidProducer)
return null; return null;
Thing producer = producerComp.Producer; Thing producer = producerComp.Producer;
IntVec3 center = producer.Position; IntVec3 center = producer.Position;
return (Pawn)AttackTargetFinder.BestAttackTarget( return (Thing)AttackTargetFinder.BestAttackTarget(
pawn, pawn,
TargetScanFlags.NeedLOSToAll, TargetScanFlags.NeedThreat,
target => target is Pawn p && pawn.HostileTo(p) && p.Spawned && !p.Downed && !p.Dead, (Thing x) => ExtraTargetValidator(pawn, x),
0f, 0f,
radius, radius,
center, center,
@@ -121,6 +130,9 @@ namespace ArachnaeSwarm
JobGiver_AIDefendProducer obj = (JobGiver_AIDefendProducer)base.DeepCopy(resolve); JobGiver_AIDefendProducer obj = (JobGiver_AIDefendProducer)base.DeepCopy(resolve);
obj.attackMeleeThreatEvenIfNotHostile = attackMeleeThreatEvenIfNotHostile; obj.attackMeleeThreatEvenIfNotHostile = attackMeleeThreatEvenIfNotHostile;
obj.defendRadius = defendRadius; obj.defendRadius = defendRadius;
obj.onlyDefendDrafted = onlyDefendDrafted;
obj.excludeDormantMechs = excludeDormantMechs;
obj.includeHostileTurrets = includeHostileTurrets;
return obj; return obj;
} }

View File

@@ -10,18 +10,6 @@ namespace ArachnaeSwarm
/// </summary> /// </summary>
public class ThinkNode_ConditionalNotProducedByMechCarrier : ThinkNode_Conditional public class ThinkNode_ConditionalNotProducedByMechCarrier : ThinkNode_Conditional
{ {
// 可选:是否检查生产者是否存活
private bool checkProducerAlive = true;
// 可选:是否检查生产者是否在同一地图
private bool checkSameMap = false;
// 可选:是否检查生产者是否可到达
private bool checkReachable = false;
// 可选是否检查生产者类型pawn必须征召才跟随
private bool checkProducerTypeConditions = true;
public ThinkNode_ConditionalNotProducedByMechCarrier() public ThinkNode_ConditionalNotProducedByMechCarrier()
{ {
} }
@@ -29,7 +17,7 @@ namespace ArachnaeSwarm
protected override bool Satisfied(Pawn pawn) protected override bool Satisfied(Pawn pawn)
{ {
// 基础检查如果不是生产者生产的返回true // 基础检查如果不是生产者生产的返回true
bool isProduced = IsProducedByMechCarrier(pawn); bool isProduced = HasProducer(pawn);
// 如果是生产者生产的,再检查其他条件 // 如果是生产者生产的,再检查其他条件
if (isProduced) if (isProduced)
@@ -44,7 +32,7 @@ namespace ArachnaeSwarm
/// <summary> /// <summary>
/// 检查pawn是否由生产者生产 /// 检查pawn是否由生产者生产
/// </summary> /// </summary>
private bool IsProducedByMechCarrier(Pawn pawn) private bool HasProducer(Pawn pawn)
{ {
if (!pawn.Spawned) if (!pawn.Spawned)
return false; return false;
@@ -58,33 +46,6 @@ namespace ArachnaeSwarm
if (producer == null || producer.Destroyed) if (producer == null || producer.Destroyed)
return false; return false;
// 检查生产者是否在同一地图
if (checkSameMap && producer.Map != pawn.Map)
return false;
// 检查是否可以到达生产者
if (checkReachable && !pawn.CanReach(producer, PathEndMode.OnCell, Danger.Deadly))
return false;
// 根据生产者类型检查特定条件
if (checkProducerTypeConditions && producer is Pawn pawnProducer)
{
// 如果生产者是pawn则只在征召状态下才跟随
// 这是为了模拟原版动物跟随主人的逻辑
if (checkProducerAlive && (pawnProducer.Dead || pawnProducer.Downed))
return false;
// 只有在征召状态下才认为需要跟随
if (!pawnProducer.Drafted)
return false;
}
else if (checkProducerTypeConditions && producer is Building buildingProducer)
{
// 如果生产者是建筑默认返回true
// 可以根据需要添加其他条件
return true;
}
return true; return true;
} }
} }

View File

@@ -6,16 +6,40 @@ using Verse.AI;
namespace ArachnaeSwarm namespace ArachnaeSwarm
{ {
public class CompProducedByMechCarrier : ThingComp public class CompProducedByMechCarrier : ThingComp, IBidirectionalValidator
{ {
private Thing producer; private Thing producer;
private CompAutoMechCarrier producerComp; private CompAutoMechCarrier producerComp;
private int lastProducerCheckTick = -1; private int lastProducerCheckTick = -1;
private const int PRODUCER_CHECK_INTERVAL = 60; private const int PRODUCER_CHECK_INTERVAL = 60;
public Thing Producer => producer; // 死亡检测相关
public CompAutoMechCarrier ProducerComp => producerComp; private bool wasDead = false;
private int deathTick = -1;
private const int DEATH_CLEANUP_DELAY = 60; // 死后60tick进行清理
// 安全锁
private object validationLock = new object();
// === IBidirectionalValidator 实现 ===
public bool IsProducerValid
{
get
{
lock (validationLock)
{
if (producer == null || producer.Destroyed)
return false;
// 如果是pawn检查是否死亡或倒下
if (producer is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
}
}
// 公开属性,用于其他类访问 // 公开属性,用于其他类访问
public bool HasValidProducer public bool HasValidProducer
{ {
@@ -23,42 +47,174 @@ namespace ArachnaeSwarm
{ {
if (producer == null || producer.Destroyed) if (producer == null || producer.Destroyed)
return false; return false;
// 如果是pawn检查是否死亡或倒下 // 如果是pawn检查是否死亡或倒下
if (producer is Pawn pawn && (pawn.Dead || pawn.Downed)) if (producer is Pawn pawn && (pawn.Dead || pawn.Downed))
return false; return false;
return true; return true;
} }
} }
public Thing GetProducer()
{
lock (validationLock)
{
return IsProducerValid ? producer : null;
}
}
public bool IsProducerAlive
{
get
{
lock (validationLock)
{
return IsProducerValid && producer.Spawned;
}
}
}
public bool IsChildValid(Thing child)
{
if (child == null || child.Destroyed)
return false;
// 检查是否为pawn
if (!(child is Pawn))
return false;
// 检查是否死亡
if (child is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
public bool IsChildAlive(Thing child)
{
return IsChildValid(child) && child.Spawned;
}
public bool ValidateBidirectional(Thing child)
{
lock (validationLock)
{
// 验证子单位
if (!IsChildValid(child))
return false;
// 验证生产者
if (!IsProducerValid)
return false;
// 验证双向引用
return ValidateBidirectionalReference(child);
}
}
public bool ValidateAndExecute(Thing child, System.Action action)
{
if (!ValidateBidirectional(child))
return false;
try
{
action?.Invoke();
return true;
}
catch (System.Exception ex)
{
Log.Error($"双向验证执行失败: {ex.Message}");
return false;
}
}
private bool ValidateBidirectionalReference(Thing child)
{
// 检查生产者是否包含这个子单位
var producerCarrier = GetProducerComp();
if (producerCarrier == null)
return false;
// 验证生产者是否知道这个子单位
return producerCarrier.ValidateChildReference(child);
}
// === 接口实现结束 ===
public Thing Producer => GetProducer();
public CompAutoMechCarrier ProducerComp => GetProducerComp();
// 获取生产者组件的安全方法
private CompAutoMechCarrier GetProducerComp()
{
lock (validationLock)
{
if (!IsProducerValid)
return null;
// 如果组件为空,尝试获取
if (producerComp == null || producerComp.parent != producer)
{
producerComp = producer.TryGetComp<CompAutoMechCarrier>();
}
return producerComp;
}
}
// 检查是否应该跟随生产者 // 检查是否应该跟随生产者
public bool ShouldFollowProducer public bool ShouldFollowProducer
{ {
get get
{ {
if (!HasValidProducer) lock (validationLock)
{
if (!IsProducerValid)
return false;
// 确保pawn是有效的
Pawn pawn = parent as Pawn;
if (pawn == null || !pawn.Spawned || pawn.Downed || pawn.Dead)
return false;
// 确保生产者在同一地图且可以到达
if (producer.Map != pawn.Map || !pawn.CanReach(producer, PathEndMode.OnCell, Danger.Deadly))
return false;
return true;
}
}
}
// 初始化方法 - 安全版本
public bool InitializeSafe(Thing producer, CompAutoMechCarrier producerComp)
{
lock (validationLock)
{
// 验证生产者
if (producer == null || producer.Destroyed)
return false; return false;
// 确保pawn是有效的 // 验证生产者组件
Pawn pawn = parent as Pawn; if (producerComp == null || producerComp.parent != producer)
if (pawn == null || !pawn.Spawned || pawn.Downed || pawn.Dead)
return false; return false;
// 确保生产者在同一地图且可以到达 this.producer = producer;
if (producer.Map != pawn.Map || !pawn.CanReach(producer, PathEndMode.OnCell, Danger.Deadly)) this.producerComp = producerComp;
return false;
// 记录初始化时间
// 可以根据需要添加更多条件 lastProducerCheckTick = Find.TickManager.TicksGame;
Log.Message($"双向验证: {parent?.LabelCap} -> {producer.LabelCap} 初始化成功");
return true; return true;
} }
} }
// 初始化方法 // 原始初始化方法(保持向后兼容)
public void Initialize(Thing producer, CompAutoMechCarrier producerComp) public void Initialize(Thing producer, CompAutoMechCarrier producerComp)
{ {
this.producer = producer; InitializeSafe(producer, producerComp);
this.producerComp = producerComp;
} }
// 尝试更新生产者状态 // 尝试更新生产者状态
@@ -69,9 +225,61 @@ namespace ArachnaeSwarm
lastProducerCheckTick = Find.TickManager.TicksGame; lastProducerCheckTick = Find.TickManager.TicksGame;
// 检查生产者是否仍然有效 lock (validationLock)
if (producer != null && (producer.Destroyed || (producer is Pawn p && (p.Dead || p.Downed))))
{ {
// 检查生产者是否仍然有效
if (producer != null && (producer.Destroyed || (producer is Pawn p && (p.Dead || p.Downed))))
{
Log.Warning($"生产者无效: {producer?.LabelCap}, 清除引用");
producer = null;
producerComp = null;
}
// 检查自身状态
CheckSelfStatus();
}
}
// 检查自身状态
private void CheckSelfStatus()
{
// 检查是否死亡
if (parent is Pawn pawn)
{
if (pawn.Dead)
{
if (!wasDead)
{
wasDead = true;
deathTick = Find.TickManager.TicksGame;
Log.Message($"子单位死亡: {pawn.LabelCap}, 准备通知生产者");
}
// 死亡后延迟清理
if (deathTick >= 0 && Find.TickManager.TicksGame - deathTick >= DEATH_CLEANUP_DELAY)
{
NotifyProducerOfDeath();
}
}
else
{
wasDead = false;
deathTick = -1;
}
}
}
// 通知生产者自己死亡
private void NotifyProducerOfDeath()
{
lock (validationLock)
{
if (producerComp != null && !producerComp.parent.Destroyed)
{
producerComp.NotifyChildDeath(parent);
}
// 清除引用
producer = null; producer = null;
producerComp = null; producerComp = null;
} }
@@ -80,38 +288,112 @@ namespace ArachnaeSwarm
// 获取生产者的位置 // 获取生产者的位置
public IntVec3 GetProducerPosition() public IntVec3 GetProducerPosition()
{ {
if (!HasValidProducer) lock (validationLock)
return IntVec3.Invalid; {
if (!IsProducerValid)
return producer.Position; return IntVec3.Invalid;
return producer.Position;
}
} }
// 获取生产者的交互单元格 // 获取生产者的交互单元格
public IntVec3 GetProducerInteractionCell() public IntVec3 GetProducerInteractionCell()
{ {
if (!HasValidProducer) lock (validationLock)
return IntVec3.Invalid; {
if (!IsProducerValid)
if (producer is Building building) return IntVec3.Invalid;
return building.InteractionCell;
if (producer is Building building)
return producer.Position; return building.InteractionCell;
return producer.Position;
}
} }
// 检查是否在生产者附近 // 检查是否在生产者附近
public bool IsNearProducer(Pawn pawn, float radius) public bool IsNearProducer(Pawn pawn, float radius)
{ {
if (!HasValidProducer) lock (validationLock)
return false; {
if (!IsProducerValid)
return pawn.Position.DistanceTo(producer.Position) <= radius; return false;
return pawn.Position.DistanceTo(producer.Position) <= radius;
}
}
// === Tick 方法 ===
public override void CompTick()
{
base.CompTick();
try
{
// 定期检查生产者状态
TryUpdateProducerStatus();
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier Tick错误: {ex.Message}");
}
}
public override void CompTickRare()
{
base.CompTickRare();
try
{
// 定期清理
lock (validationLock)
{
if (producer != null && producer.Destroyed)
{
producer = null;
producerComp = null;
}
}
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier TickRare错误: {ex.Message}");
}
} }
public override void PostExposeData() public override void PostExposeData()
{ {
base.PostExposeData(); base.PostExposeData();
Scribe_References.Look(ref producer, "producer");
Scribe_Values.Look(ref lastProducerCheckTick, "lastProducerCheckTick", -1); try
{
Scribe_References.Look(ref producer, "producer");
Scribe_Values.Look(ref lastProducerCheckTick, "lastProducerCheckTick", -1);
Scribe_Values.Look(ref wasDead, "wasDead", false);
Scribe_Values.Look(ref deathTick, "deathTick", -1);
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier 序列化错误: {ex.Message}");
}
}
// === 调试方法 ===
public string GetValidationStatus()
{
lock (validationLock)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine($"=== {parent?.LabelCap} 验证状态 ===");
sb.AppendLine($"生产者有效: {IsProducerValid}");
sb.AppendLine($"生产者存活: {IsProducerAlive}");
sb.AppendLine($"生产者: {producer?.LabelCap ?? "NULL"}");
sb.AppendLine($"生产者组件: {producerComp != null}");
sb.AppendLine($"上次检查: {lastProducerCheckTick}");
return sb.ToString();
}
} }
} }
} }

View File

@@ -0,0 +1,26 @@
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 双向安全校验接口
/// 确保生产者和子单位在操作前互相验证存在
/// </summary>
public interface IBidirectionalValidator
{
// 生产者相关
bool IsProducerValid { get; }
Thing GetProducer();
bool IsProducerAlive { get; }
// 子单位相关
bool IsChildValid(Thing child);
bool IsChildAlive(Thing child);
// 双向验证
bool ValidateBidirectional(Thing child);
bool ValidateAndExecute(Thing child, System.Action action);
}
}