This commit is contained in:
2026-02-13 11:58:35 +08:00
parent 033a618921
commit 5145fb51f9
15 changed files with 1860 additions and 113 deletions

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<AbilityDef ParentName="AbilityTouchBase">
<defName>ARA_BindDrone</defName>
<label>信息素标记</label>
<description>使用信息素标记一只阿拉克涅督虫(包括野生虫群子个体),受到标记的督虫和其麾下的辅虫将誓死效忠于女皇种,并与其建立心灵链接。\n\n除了手动链接外女皇种也会每60秒尝试自动链接己方所有未链接的阿拉克涅督虫此类链接和手动链接不一样,不需要目视</description>
<description>使用信息素标记一只野生阿拉克涅督虫或兽虫个体,其将脱离野兽状态,誓死效忠于女皇种,并与其建立心灵链接。\n\n对于己方的督虫和兽虫女皇种会自动与其建立链接,不需要技能</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_BindDrone</iconPath> <!-- Placeholder: You'll need to create this icon -->
<hotKey>Misc1</hotKey>

View File

@@ -256,6 +256,25 @@
<minSeverity>0</minSeverity>
</li>
</stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_GestaltNode">
<nodeType>HiveNode</nodeType>
</li>
<!-- <li Class="ArachnaeSwarm.HediffCompProperties_HiveMindDrone">
<unlinkedDieDelayTicks>6400</unlinkedDieDelayTicks>
</li> -->
<!-- <li Class="HediffCompProperties_MessageAfterTicks">
<ticks>1</ticks>
<letterLabel>{0_labelShort} 诞生</letterLabel>
<letterText>一只新的阿拉克涅督虫 {0_labelShort} 已经破茧而出!她正在四处徘徊,等待女皇种的指示——使用阿拉克涅女皇种的信息素标记技能完成链接,或者等待其自行建立链接。</letterText>
<letterType>HumanPregnancy</letterType>
</li> -->
<li Class="HediffCompProperties_RemoveIfOtherHediff">
<hediffs>
<li>ARA_NonPlayer_HiveMindDroneHediff</li>
</hediffs>
</li>
</comps>
</HediffDef>
<HediffDef>

View File

@@ -297,6 +297,9 @@
<def>CrumblingMind</def>
<severity>0.01</severity>
</li>
<li>
<def>ARA_NonPlayer_HiveMindDroneHediff</def>
</li>
</startingHediffs>
</PawnKindDef>

View File

@@ -60,6 +60,7 @@
</apparelTags>
<apparelMoney>0</apparelMoney>
<abilities>
<li>ARA_BindDrone</li>
<li>ARA_AcidSprayBurst_Queen</li>
<li>ARA_TumorSpew</li>
</abilities>
@@ -169,6 +170,7 @@
</apparelTags>
<apparelMoney>0</apparelMoney>
<abilities>
<li>ARA_BindDrone</li>
<li>ARA_Neurotyrant_Harvest</li>
<li>ARA_Neurotyrant_PsychicLoadDump</li>
</abilities>

View File

@@ -1750,8 +1750,19 @@
<li Class="ArachnaeSwarm.CompProperties_HediffGiver">
<hediffs>
<li>ARA_Psi_Master</li>
<li>PsychicAmplifier</li>
</hediffs>
<!-- 自定义部位映射 -->
<customBodyPartMapping>
<li>
<hediff>PsychicAmplifier</hediff>
<bodyPart>Brain</bodyPart>
<priority>1</priority>
<chooseRandomPart>false</chooseRandomPart>
<fallbackToDefault>true</fallbackToDefault>
</li>
</customBodyPartMapping>
<addChance>1.0</addChance>
<allowDuplicates>false</allowDuplicates>
</li>

View File

@@ -3,27 +3,55 @@
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\harmonypatches\\patch_pawn_needstracker_shouldhaveneed.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_pawnresearchblueprintreader\\comp_pawnresearchblueprintreader.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_pawnresearchblueprintreader\\comp_pawnresearchblueprintreader.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_pawnresearchblueprintreader\\gizmo_pawnresearchprogress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_pawnresearchblueprintreader\\gizmo_pawnresearchprogress.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_pawnresearchblueprintreader\\compproperties_pawnresearchblueprintreader.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_pawnresearchblueprintreader\\compproperties_pawnresearchblueprintreader.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_hivemind\\compabilityeffect_binddrone.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hivemind\\compabilityeffect_binddrone.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_swarmspellholder\\comp_swarmspellholder.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_swarmspellholder\\comp_swarmspellholder.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_researchblueprintreader\\building_researchblueprintreader.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_researchblueprintreader\\building_researchblueprintreader.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_comphediffgiver\\comphediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_comphediffgiver\\comphediffgiver.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\\harmonypatches\\patch_pawn_needstracker_shouldhaveneed.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\patch_pawn_needstracker_shouldhaveneed.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\\harmonypatches\\patch_draftableanimals.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\\harmonypatches\\patch_draftableanimals.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\patch_draftableanimals.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\\harmonypatches\\projectile_launch_patch.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\\harmonypatches\\projectile_launch_patch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\projectile_launch_patch.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\\harmonypatches\\patch_researchmanager_addremovemethod.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\\harmonypatches\\patch_researchmanager_addremovemethod.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\patch_researchmanager_addremovemethod.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\\harmonypatches\\patch_plantpollutionnullcheck.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\\harmonypatches\\patch_plantpollutionnullcheck.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\patch_plantpollutionnullcheck.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\\harmonypatches\\patch_forcetargetable.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\\harmonypatches\\patch_forcetargetable.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:harmonypatches\\patch_forcetargetable.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
@@ -62,10 +90,6 @@
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_psychicloaddump\\compproperties_abilitypsychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloaddump\\compproperties_abilitypsychicloaddump.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_swarmspellholder\\comp_swarmspellholder.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_swarmspellholder\\comp_swarmspellholder.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_swarmspellholder\\gizmo_swarmspellstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_swarmspellholder\\gizmo_swarmspellstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
@@ -134,28 +158,91 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 6,
"SelectedChildIndex": 3,
"Children": [
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "Projectile_Launch_Patch.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Projectile_Launch_Patch.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Projectile_Launch_Patch.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Projectile_Launch_Patch.cs",
"RelativeToolTip": "HarmonyPatches\\Projectile_Launch_Patch.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:03:01.656Z",
"EditorCaption": ""
},
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Gizmo_PawnResearchProgress.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs*",
"RelativeToolTip": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs*",
"ViewState": "AgIAAMQAAAAAAAAAAAAhwNYAAAAUAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T03:54:02.036Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "CompProperties_PawnResearchBlueprintReader.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\CompProperties_PawnResearchBlueprintReader.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\CompProperties_PawnResearchBlueprintReader.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\CompProperties_PawnResearchBlueprintReader.cs*",
"RelativeToolTip": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\CompProperties_PawnResearchBlueprintReader.cs*",
"ViewState": "AgIAAC0AAAAAAAAAAAAawD8AAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T03:54:00.997Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Comp_PawnResearchBlueprintReader.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs*",
"RelativeToolTip": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs*",
"ViewState": "AgIAAA8DAAAAAAAAAAAewCIDAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T03:53:59.347Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "CompAbilityEffect_BindDrone.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HiveMind\\CompAbilityEffect_BindDrone.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HiveMind\\CompAbilityEffect_BindDrone.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HiveMind\\CompAbilityEffect_BindDrone.cs",
"RelativeToolTip": "Hediffs\\ARA_HiveMind\\CompAbilityEffect_BindDrone.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAALYAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T02:39:33.878Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "Building_ResearchBlueprintReader.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\Building_ResearchBlueprintReader.cs",
"RelativeDocumentMoniker": "Buildings\\Building_ResearchBlueprintReader\\Building_ResearchBlueprintReader.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\Building_ResearchBlueprintReader.cs",
"RelativeToolTip": "Buildings\\Building_ResearchBlueprintReader\\Building_ResearchBlueprintReader.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAACIAAAAPAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T02:24:37.654Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "CompHediffGiver.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAHoAAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-13T02:14:47.422Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "Patch_ResearchManager_AddRemoveMethod.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_ResearchManager_AddRemoveMethod.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Patch_ResearchManager_AddRemoveMethod.cs",
@@ -163,12 +250,11 @@
"RelativeToolTip": "HarmonyPatches\\Patch_ResearchManager_AddRemoveMethod.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:02:58.905Z",
"EditorCaption": ""
"WhenOpened": "2026-02-11T03:02:58.905Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"DocumentIndex": 11,
"Title": "Patch_PlantPollutionNullCheck.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_PlantPollutionNullCheck.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Patch_PlantPollutionNullCheck.cs",
@@ -176,12 +262,11 @@
"RelativeToolTip": "HarmonyPatches\\Patch_PlantPollutionNullCheck.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:02:49.024Z",
"EditorCaption": ""
"WhenOpened": "2026-02-11T03:02:49.024Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"DocumentIndex": 12,
"Title": "Patch_ForceTargetable.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_ForceTargetable.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Patch_ForceTargetable.cs",
@@ -189,12 +274,35 @@
"RelativeToolTip": "HarmonyPatches\\Patch_ForceTargetable.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:02:45.4Z",
"EditorCaption": ""
"WhenOpened": "2026-02-11T03:02:45.4Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"DocumentIndex": 4,
"Title": "Comp_SwarmSpellHolder.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"ViewState": "AgIAAFYCAAAAAAAAAAAAAHADAAAyAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-30T07:11:59.797Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "Projectile_Launch_Patch.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Projectile_Launch_Patch.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Projectile_Launch_Patch.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Projectile_Launch_Patch.cs",
"RelativeToolTip": "HarmonyPatches\\Projectile_Launch_Patch.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:03:01.656Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "Patch_DraftableAnimals.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_DraftableAnimals.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Patch_DraftableAnimals.cs",
@@ -202,25 +310,23 @@
"RelativeToolTip": "HarmonyPatches\\Patch_DraftableAnimals.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T03:01:45.903Z",
"EditorCaption": ""
"WhenOpened": "2026-02-11T03:01:45.903Z"
},
{
"$type": "Document",
"DocumentIndex": 0,
"DocumentIndex": 7,
"Title": "Patch_Pawn_NeedsTracker_ShouldHaveNeed.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_Pawn_NeedsTracker_ShouldHaveNeed.cs",
"RelativeDocumentMoniker": "HarmonyPatches\\Patch_Pawn_NeedsTracker_ShouldHaveNeed.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\HarmonyPatches\\Patch_Pawn_NeedsTracker_ShouldHaveNeed.cs",
"RelativeToolTip": "HarmonyPatches\\Patch_Pawn_NeedsTracker_ShouldHaveNeed.cs",
"ViewState": "AgIAAA4AAAAAAAAAAADwvxYAAAAdAAAAAAAAAA==",
"ViewState": "AgIAAA4AAAAAAAAAAAAwwBYAAAAdAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T02:46:06.897Z",
"EditorCaption": ""
"WhenOpened": "2026-02-11T02:46:06.897Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"DocumentIndex": 13,
"Title": "TravelingWormhole.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\TravelingWormhole.cs",
"RelativeDocumentMoniker": "Buildings\\Wormhole\\TravelingWormhole.cs",
@@ -232,7 +338,7 @@
},
{
"$type": "Document",
"DocumentIndex": 7,
"DocumentIndex": 14,
"Title": "CompLaunchableWormhole.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\CompLaunchableWormhole.cs",
"RelativeDocumentMoniker": "Buildings\\Wormhole\\CompLaunchableWormhole.cs",
@@ -244,7 +350,7 @@
},
{
"$type": "Document",
"DocumentIndex": 8,
"DocumentIndex": 15,
"Title": "UniquePawnManager.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs",
@@ -256,7 +362,7 @@
},
{
"$type": "Document",
"DocumentIndex": 9,
"DocumentIndex": 16,
"Title": "CompUniquePawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs",
@@ -268,7 +374,7 @@
},
{
"$type": "Document",
"DocumentIndex": 11,
"DocumentIndex": 18,
"Title": "JobDriver_ExtractHoney.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
@@ -280,7 +386,7 @@
},
{
"$type": "Document",
"DocumentIndex": 10,
"DocumentIndex": 17,
"Title": "Need_HoneyProduction.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_HoneyProduction.cs",
"RelativeDocumentMoniker": "Needs\\Need_HoneyProduction.cs",
@@ -292,7 +398,7 @@
},
{
"$type": "Document",
"DocumentIndex": 12,
"DocumentIndex": 19,
"Title": "Need_ChitinArmor.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_ChitinArmor.cs",
"RelativeDocumentMoniker": "Needs\\Need_ChitinArmor.cs",
@@ -304,7 +410,7 @@
},
{
"$type": "Document",
"DocumentIndex": 14,
"DocumentIndex": 21,
"Title": "CompProperties_AbilityPsychicLoadDump.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs",
@@ -316,7 +422,7 @@
},
{
"$type": "Document",
"DocumentIndex": 13,
"DocumentIndex": 20,
"Title": "CompAbilityEffect_PsychicLoadDump.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs",
@@ -328,7 +434,7 @@
},
{
"$type": "Document",
"DocumentIndex": 18,
"DocumentIndex": 24,
"Title": "CompAbilityEffect_PsychicResearchHarvest.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs",
@@ -340,7 +446,7 @@
},
{
"$type": "Document",
"DocumentIndex": 22,
"DocumentIndex": 28,
"Title": "CompProperties_AbilityPsychicLoadCost.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs",
@@ -352,7 +458,7 @@
},
{
"$type": "Document",
"DocumentIndex": 21,
"DocumentIndex": 27,
"Title": "SwarmSpellUtility.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs",
@@ -364,7 +470,7 @@
},
{
"$type": "Document",
"DocumentIndex": 17,
"DocumentIndex": 23,
"Title": "CompAbilityEffect_PsychicLoadCost.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs",
@@ -376,19 +482,7 @@
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "Comp_SwarmSpellHolder.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"ViewState": "AgIAAFgCAAAAAAAAAAAYwGkCAAASAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-30T07:11:59.797Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"DocumentIndex": 22,
"Title": "Gizmo_SwarmSpellStatus.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs",
@@ -400,7 +494,7 @@
},
{
"$type": "Document",
"DocumentIndex": 23,
"DocumentIndex": 29,
"Title": "CompAbilityEffect_HediffGacha.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs",
@@ -412,7 +506,7 @@
},
{
"$type": "Document",
"DocumentIndex": 20,
"DocumentIndex": 26,
"Title": "CompFighterInvisible.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs",
@@ -424,7 +518,7 @@
},
{
"$type": "Document",
"DocumentIndex": 19,
"DocumentIndex": 25,
"Title": "CompProperties_AbilityPsychicResearchHarvest.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs",
@@ -436,7 +530,7 @@
},
{
"$type": "Document",
"DocumentIndex": 24,
"DocumentIndex": 30,
"Title": "CompAbilityEffect_HediffRestriction.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs",
@@ -448,7 +542,7 @@
},
{
"$type": "Document",
"DocumentIndex": 25,
"DocumentIndex": 31,
"Title": "Window_HediffSelection.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs",
@@ -460,7 +554,7 @@
},
{
"$type": "Document",
"DocumentIndex": 26,
"DocumentIndex": 32,
"Title": "ARA_PowerArmor.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PowerArmor\\ARA_PowerArmor.cs",
"RelativeDocumentMoniker": "PowerArmor\\ARA_PowerArmor.cs",
@@ -472,7 +566,7 @@
},
{
"$type": "Document",
"DocumentIndex": 27,
"DocumentIndex": 33,
"Title": "PawnCapacityWorker_PsychicStange.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs",
"RelativeDocumentMoniker": "PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs",
@@ -484,7 +578,7 @@
},
{
"$type": "Document",
"DocumentIndex": 29,
"DocumentIndex": 35,
"Title": "CompAbilityEffect_PsychicBrainburn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs",
"RelativeDocumentMoniker": "Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs",
@@ -496,7 +590,7 @@
},
{
"$type": "Document",
"DocumentIndex": 28,
"DocumentIndex": 34,
"Title": "ARA_DefOf.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
"RelativeDocumentMoniker": "ARA_DefOf.cs",
@@ -508,7 +602,7 @@
},
{
"$type": "Document",
"DocumentIndex": 30,
"DocumentIndex": 36,
"Title": "CompAutoMechCarrier.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",

View File

@@ -366,6 +366,9 @@
<Compile Include="Pawn_Comps\ARA_HoneyProduction_Animal\CompHoneyProduction_Animal.cs" />
<Compile Include="Pawn_Comps\ARA_NodeSwarmLifetime\CompNodeSwarmLifetime.cs" />
<Compile Include="Pawn_Comps\ARA_NodeSwarmLifetime\CompProperties_NodeSwarmLifetime.cs" />
<Compile Include="Pawn_Comps\ARA_PawnResearchBlueprintReader\CompProperties_PawnResearchBlueprintReader.cs" />
<Compile Include="Pawn_Comps\ARA_PawnResearchBlueprintReader\Comp_PawnResearchBlueprintReader.cs" />
<Compile Include="Pawn_Comps\ARA_PawnResearchBlueprintReader\Gizmo_PawnResearchProgress.cs" />
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\CompProperties_SwarmMaintainer.cs" />
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\Comp_SwarmMaintainer.cs" />
<Compile Include="Pawn_Comps\ARA_SwarmSpellHolder\Comp_SwarmSpellHolder.cs" />

View File

@@ -66,13 +66,16 @@ namespace ArachnaeSwarm
}
// 3. 添加 ARA_HiveMindDrone
HediffDef hiveMindDroneDef = HediffDef.Named("ARA_HiveMindDrone");
if (hiveMindDroneDef != null && !dronePawn.health.hediffSet.HasHediff(hiveMindDroneDef))
if (dronePawn.IsAnimal)
{
dronePawn.health.AddHediff(hiveMindDroneDef);
dronePawn.health.AddHediff(HediffDef.Named("ARA_LifespanHediff"));
ArachnaeLog.Debug($"Added ARA_HiveMindDrone to {dronePawn.LabelShort}");
dronePawn.health.AddHediff(HediffDef.Named("ARA_HiveMindBeast"));
}
else
{
dronePawn.health.AddHediff(HediffDef.Named("ARA_HiveMindDrone"));
}
dronePawn.health.AddHediff(HediffDef.Named("ARA_LifespanHediff"));
ArachnaeLog.Debug($"Added ARA_HiveMindDrone to {dronePawn.LabelShort}");
// 4. 尝试绑定到主节点
Hediff_HiveMindMaster masterHediff = masterPawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("ARA_HiveMindMaster")) as Hediff_HiveMindMaster;

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;
@@ -7,7 +8,11 @@ namespace ArachnaeSwarm
{
public class CompHediffGiver : ThingComp
{
private bool hediffsApplied = false; // 新增:标记是否已经应用过hediff
private bool hediffsApplied = false; // 标记是否已经应用过hediff
// 用于记录添加的hediff和部位用于调试和撤销
private Dictionary<HediffDef, List<BodyPartRecord>> appliedHediffParts =
new Dictionary<HediffDef, List<BodyPartRecord>>();
public CompProperties_HediffGiver Props => (CompProperties_HediffGiver)this.props;
@@ -18,7 +23,7 @@ namespace ArachnaeSwarm
// 只有当thing是pawn时才添加hediff
if (this.parent is Pawn pawn)
{
// 新增:检查是否已经应用过hediff或者是否是读档
// 检查是否已经应用过hediff或者是否是读档
if (!hediffsApplied && !respawningAfterLoad)
{
AddHediffsToPawn(pawn);
@@ -37,6 +42,16 @@ namespace ArachnaeSwarm
if (Props.addChance < 1.0f && Rand.Value > Props.addChance)
return;
// 显示应用消息(如果有)
if (Props.showApplicationMessage && pawn.Faction == Faction.OfPlayer)
{
string message = Props.applicationMessageKey != null
? Props.applicationMessageKey.Translate(pawn.LabelShort)
: "ARA_HediffGiver_Applied".Translate(pawn.LabelShort, Props.hediffs.Count);
Messages.Message(message, pawn, MessageTypeDefOf.NeutralEvent);
}
// 为每个hediff添加到pawn
foreach (HediffDef hediffDef in Props.hediffs)
{
@@ -46,60 +61,272 @@ namespace ArachnaeSwarm
// === 新增:获取应应用的部位 ===
BodyPartDef bodyPartDef = Props.GetBodyPartForHediff(hediffDef);
BodyPartRecord bodyPartRecord = null;
List<BodyPartRecord> bodyParts = GetBodyPartsForHediff(pawn, hediffDef, bodyPartDef);
if (bodyPartDef != null)
// 如果没有指定部位,或者没有找到匹配部位,则添加到全身
if (bodyParts == null || bodyParts.Count == 0)
{
bodyPartRecord = GetFirstMatchingBodyPart(pawn, bodyPartDef);
AddHediffToPawn(pawn, hediffDef, null);
continue;
}
// 添加hediff
if (bodyPartRecord != null)
// 根据选择规则添加hediff到相应部位
foreach (var bodyPart in bodyParts)
{
pawn.health.AddHediff(hediffDef, bodyPartRecord);
AddHediffToPawn(pawn, hediffDef, bodyPart);
}
else
// 记录应用到的部位
if (bodyParts.Count > 0)
{
pawn.health.AddHediff(hediffDef);
if (!appliedHediffParts.ContainsKey(hediffDef))
{
appliedHediffParts[hediffDef] = new List<BodyPartRecord>();
}
appliedHediffParts[hediffDef].AddRange(bodyParts);
}
}
// 播放应用效果(如果有)
if (Props.applicationEffect != null && pawn.Spawned)
{
Effecter effecter = Props.applicationEffect.Spawn();
effecter.Trigger(pawn, pawn);
effecter.Cleanup();
}
}
/// <summary>
/// 获取第一个匹配的身体部位记录
/// 添加hediff到pawn的指定部位
/// </summary>
private BodyPartRecord GetFirstMatchingBodyPart(Pawn pawn, BodyPartDef bodyPartDef)
private void AddHediffToPawn(Pawn pawn, HediffDef hediffDef, BodyPartRecord bodyPart)
{
if (pawn == null || bodyPartDef == null || pawn.RaceProps?.body == null)
try
{
Hediff hediff = HediffMaker.MakeHediff(hediffDef, pawn, bodyPart);
// 设置严重度(如果有指定)
if (Props.initialSeverity >= 0f)
{
hediff.Severity = Props.initialSeverity;
}
// 添加hediff
pawn.health.AddHediff(hediff);
ArachnaeLog.Debug($"Added hediff {hediffDef.defName} to {pawn.Label} " +
$"{(bodyPart != null ? $"on {bodyPart.def.defName}" : "to whole body")}");
}
catch (Exception)
{
}
}
/// <summary>
/// 获取hediff应应用的身体部位列表
/// </summary>
private List<BodyPartRecord> GetBodyPartsForHediff(Pawn pawn, HediffDef hediffDef, BodyPartDef bodyPartDef)
{
if (pawn == null || pawn.RaceProps?.body == null)
return null;
// 如果没有指定身体部位,返回空列表
if (bodyPartDef == null)
return null;
try
{
// 获取所有匹配的身体部位
List<BodyPartRecord> matchingParts = pawn.RaceProps.body.GetPartsWithDef(bodyPartDef);
List<BodyPartRecord> allMatchingParts = pawn.RaceProps.body.GetPartsWithDef(bodyPartDef);
if (matchingParts != null && matchingParts.Count > 0)
if (allMatchingParts == null || allMatchingParts.Count == 0)
{
// 返回第一个可用的部位
return matchingParts[0];
// 如果没有找到匹配部位,检查是否有备用部位
var mapping = Props.GetMappingForHediff(hediffDef);
if (mapping != null && mapping.fallbackToDefault)
{
// 使用默认方式添加(全身)
return null;
}
return new List<BodyPartRecord>();
}
}
catch (Exception ex)
{
ArachnaeLog.Debug($"Error getting body part for {bodyPartDef.defName}: {ex.Message}");
}
return null;
// 检查部位有效性
if (Props.checkPartValidity)
{
allMatchingParts = allMatchingParts.Where(part => IsBodyPartValid(pawn, part)).ToList();
}
if (allMatchingParts.Count == 0)
{
return new List<BodyPartRecord>();
}
// 获取选择规则
BodyPartSelectionRule rule = Props.GetPartSelectionRuleForHediff(hediffDef);
var mappingConfig = Props.GetMappingForHediff(hediffDef);
// 根据规则选择部位
List<BodyPartRecord> selectedParts = new List<BodyPartRecord>();
if (rule == null)
{
// 默认规则:使用第一个匹配的部位
selectedParts.Add(allMatchingParts[0]);
}
else
{
// 根据规则选择部位
switch (rule.mode)
{
case BodyPartSelectionMode.First:
selectedParts.Add(allMatchingParts[0]);
break;
case BodyPartSelectionMode.Random:
int count = Math.Min(rule.maxParts, allMatchingParts.Count);
selectedParts = allMatchingParts.InRandomOrder().Take(count).ToList();
break;
case BodyPartSelectionMode.All:
selectedParts = allMatchingParts;
break;
case BodyPartSelectionMode.MostDamaged:
var mostDamaged = allMatchingParts.OrderByDescending(p => GetPartDamage(pawn, p)).FirstOrDefault();
if (mostDamaged != null) selectedParts.Add(mostDamaged);
break;
case BodyPartSelectionMode.LeastDamaged:
var leastDamaged = allMatchingParts.OrderBy(p => GetPartDamage(pawn, p)).FirstOrDefault();
if (leastDamaged != null) selectedParts.Add(leastDamaged);
break;
}
// 如果配置了随机选择部位
if (mappingConfig != null && mappingConfig.chooseRandomPart)
{
selectedParts = allMatchingParts.InRandomOrder().Take(1).ToList();
}
// 处理对称性
if (rule.symmetrical && selectedParts.Count > 0)
{
selectedParts = GetSymmetricalParts(pawn, selectedParts[0], allMatchingParts);
}
}
return selectedParts;
}
catch (Exception)
{
return null;
}
}
// 新增序列化hediffsApplied标记
/// <summary>
/// 获取对称的身体部位
/// </summary>
private List<BodyPartRecord> GetSymmetricalParts(Pawn pawn, BodyPartRecord referencePart, List<BodyPartRecord> allParts)
{
List<BodyPartRecord> symmetricalParts = new List<BodyPartRecord> { referencePart };
// 查找对称部位(如左臂对应的右臂)
foreach (var part in allParts)
{
if (part != referencePart && part.def == referencePart.def)
{
// 简单的对称检测:检查部位标签或名称
if (IsSymmetricalPart(referencePart, part))
{
symmetricalParts.Add(part);
}
}
}
return symmetricalParts;
}
/// <summary>
/// 检查两个部位是否对称
/// </summary>
private bool IsSymmetricalPart(BodyPartRecord part1, BodyPartRecord part2)
{
// 简单的对称检测逻辑
string label1 = part1.customLabel ?? part1.def.label;
string label2 = part2.customLabel ?? part2.def.label;
// 检查是否包含对称标识符
string[] symmetryKeywords = { "Left", "Right", "Left", "Right", "Front", "Back", "Upper", "Lower" };
foreach (var keyword in symmetryKeywords)
{
if (label1.Contains(keyword) && label2.Contains(keyword))
{
// 检查是否是对称的关键词对
if ((keyword == "Left" && label2.Contains("Right")) ||
(keyword == "Right" && label2.Contains("Left")) ||
(keyword == "Front" && label2.Contains("Back")) ||
(keyword == "Back" && label2.Contains("Front")))
{
return true;
}
}
}
return false;
}
/// <summary>
/// 检查身体部位是否有效
/// </summary>
private bool IsBodyPartValid(Pawn pawn, BodyPartRecord part)
{
if (part == null)
return false;
// 检查部位是否已完全损坏
if (pawn.health.hediffSet.PartIsMissing(part))
return false;
// 检查部位是否被覆盖(如被装备遮挡)
// 这里可以添加更多有效性检查
return true;
}
/// <summary>
/// 获取部位的伤害值
/// </summary>
private float GetPartDamage(Pawn pawn, BodyPartRecord part)
{
if (part == null)
return 0f;
float totalDamage = 0f;
foreach (var hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.Part == part && hediff is Hediff_Injury injury)
{
totalDamage += injury.Severity;
}
}
return totalDamage;
}
// 序列化hediffsApplied标记
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref hediffsApplied, "hediffsApplied", false);
// 新增序列化已应用的hediff部位记录
Scribe_Collections.Look(ref appliedHediffParts, "appliedHediffParts",
LookMode.Def, LookMode.Deep);
}
// 新增:调试方法用于手动触发hediff添加仅开发模式
// 调试方法用于手动触发hediff添加仅开发模式
public void DebugApplyHediffs()
{
if (this.parent is Pawn pawn && !hediffsApplied)
@@ -111,7 +338,7 @@ namespace ArachnaeSwarm
}
/// <summary>
/// === 新增:获取已应用的hediff信息用于调试 ===
/// 获取已应用的hediff信息用于调试
/// </summary>
public string GetAppliedHediffInfo()
{
@@ -123,11 +350,16 @@ namespace ArachnaeSwarm
foreach (var hediffDef in Props.hediffs)
{
var hediff = pawn.health.hediffSet.GetFirstHediffOfDef(hediffDef);
if (hediff != null)
var hediffs = pawn.health.hediffSet.hediffs.Where(h => h.def == hediffDef).ToList();
if (hediffs.Count > 0)
{
string partInfo = hediff.Part?.def?.defName ?? "No specific part";
result.AppendLine($"- {hediffDef.defName} on {partInfo}");
result.AppendLine($"- {hediffDef.defName} ({hediffs.Count} instances):");
foreach (var hediff in hediffs)
{
string partInfo = hediff.Part?.def?.defName ?? "No specific part";
result.AppendLine($" * On {partInfo}, Severity: {hediff.Severity:F2}");
}
}
else
{
@@ -137,5 +369,42 @@ namespace ArachnaeSwarm
return result.ToString();
}
/// <summary>
/// 新增移除所有由该组件添加的hediff
/// </summary>
public void RemoveAppliedHediffs()
{
if (!(this.parent is Pawn pawn) || !hediffsApplied)
return;
int removedCount = 0;
foreach (var hediffDef in Props.hediffs)
{
var hediffs = pawn.health.hediffSet.hediffs.Where(h => h.def == hediffDef).ToList();
foreach (var hediff in hediffs)
{
pawn.health.RemoveHediff(hediff);
removedCount++;
}
}
hediffsApplied = false;
appliedHediffParts.Clear();
ArachnaeLog.Debug($"Removed {removedCount} hediffs from {pawn.Label}");
}
/// <summary>
/// 新增检查特定hediff是否已应用到指定部位
/// </summary>
public bool HasHediffOnPart(HediffDef hediffDef, BodyPartRecord part)
{
if (!(this.parent is Pawn pawn) || !hediffsApplied)
return false;
return pawn.health.hediffSet.hediffs
.Any(h => h.def == hediffDef && h.Part == part);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Verse;
namespace ArachnaeSwarm
@@ -10,6 +11,51 @@ namespace ArachnaeSwarm
{
public HediffDef hediff;
public BodyPartDef bodyPart;
/// <summary>
/// 可选优先级数值越大优先级越高默认1
/// </summary>
public int priority = 1;
/// <summary>
/// 可选是否随机选择多个部位如果pawn有多个相同部位
/// </summary>
public bool chooseRandomPart = false;
/// <summary>
/// 可选:如果找不到指定部位,是否使用默认添加方式
/// </summary>
public bool fallbackToDefault = true;
}
/// <summary>
/// 身体部位选择规则
/// </summary>
public class BodyPartSelectionRule
{
/// <summary>
/// 选择模式First第一个匹配的、Random随机一个、All所有匹配的
/// </summary>
public BodyPartSelectionMode mode = BodyPartSelectionMode.First;
/// <summary>
/// 仅当mode为Random时有效最多选择多少个部位
/// </summary>
public int maxParts = 1;
/// <summary>
/// 是否对称如果pawn有左右对称的相同部位
/// </summary>
public bool symmetrical = false;
}
public enum BodyPartSelectionMode
{
First, // 第一个匹配的部位
Random, // 随机选择一个匹配的部位
All, // 所有匹配的部位
MostDamaged, // 受伤最严重的部位
LeastDamaged // 受伤最轻的部位
}
public class CompProperties_HediffGiver : CompProperties
@@ -29,32 +75,134 @@ namespace ArachnaeSwarm
// === 新增自定义部位映射使用List替代Dictionary ===
public List<HediffBodyPartMapping> customBodyPartMapping = null;
// === 新增:全局身体部位选择规则 ===
public BodyPartSelectionRule globalPartSelectionRule = null;
// === 新增按hediff分类的身体部位选择规则 ===
public List<HediffPartSelectionRule> hediffPartSelectionRules = null;
// === 新增添加hediff时的严重度设置 ===
public float initialSeverity = -1f; // 负数表示使用hediff默认值
// === 新增:是否检查部位有效性(是否存在、是否已损坏等) ===
public bool checkPartValidity = true;
// === 新增:如果指定部位不存在时的备用部位 ===
public BodyPartDef fallbackBodyPart = null;
// === 新增添加hediff时的效果 ===
public EffecterDef applicationEffect = null;
// === 新增:是否在添加时显示消息 ===
public bool showApplicationMessage = false;
// === 新增:添加消息的翻译键 ===
public string applicationMessageKey = null;
// === 新增添加hediff时的声音 ===
public SoundDef applicationSound = null;
public CompProperties_HediffGiver()
{
this.compClass = typeof(CompHediffGiver);
}
/// <summary>
/// 根据hediff获取对应的身体部位定义
/// </summary>
public BodyPartDef GetBodyPartForHediff(HediffDef hediffDef)
{
if (hediffDef == null)
return null;
// 1. 首先检查自定义映射
if (customBodyPartMapping != null)
{
// 查找优先级最高的映射
HediffBodyPartMapping bestMapping = null;
int highestPriority = int.MinValue;
foreach (var mapping in customBodyPartMapping)
{
if (mapping.hediff == hediffDef)
return mapping.bodyPart;
{
if (mapping.priority > highestPriority)
{
bestMapping = mapping;
highestPriority = mapping.priority;
}
}
}
if (bestMapping != null)
{
return bestMapping.bodyPart;
}
}
// 2. 然后检查默认安装部位
if (useDefaultInstallPart && hediffDef.defaultInstallPart != null)
{
return hediffDef.defaultInstallPart;
}
return null;
// 3. 最后检查备用部位
return fallbackBodyPart;
}
/// <summary>
/// 获取hediff对应的身体部位选择规则
/// </summary>
public BodyPartSelectionRule GetPartSelectionRuleForHediff(HediffDef hediffDef)
{
if (hediffDef == null)
return globalPartSelectionRule;
// 1. 首先检查hediff特定的规则
if (hediffPartSelectionRules != null)
{
var rule = hediffPartSelectionRules.FirstOrDefault(r => r.hediff == hediffDef);
if (rule != null)
{
return rule.selectionRule;
}
}
// 2. 返回全局规则
return globalPartSelectionRule;
}
/// <summary>
/// 获取hediff对应的映射配置
/// </summary>
public HediffBodyPartMapping GetMappingForHediff(HediffDef hediffDef)
{
if (hediffDef == null || customBodyPartMapping == null)
return null;
// 查找优先级最高的映射
HediffBodyPartMapping bestMapping = null;
int highestPriority = int.MinValue;
foreach (var mapping in customBodyPartMapping)
{
if (mapping.hediff == hediffDef && mapping.priority > highestPriority)
{
bestMapping = mapping;
highestPriority = mapping.priority;
}
}
return bestMapping;
}
}
}
/// <summary>
/// Hediff与部位选择规则的映射
/// </summary>
public class HediffPartSelectionRule
{
public HediffDef hediff;
public BodyPartSelectionRule selectionRule;
}
}

View File

@@ -0,0 +1,72 @@
using RimWorld;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_PawnResearchBlueprintReader : CompProperties
{
/// <summary>
/// 是否允许该Pawn进行科技研究
/// </summary>
public bool canResearch = true;
/// <summary>
/// 研究速度乘数(基于智力等级)
/// </summary>
public float researchSpeedMultiplier = 1.0f;
/// <summary>
/// 是否显示研究进度Gizmo
/// </summary>
public bool showResearchGizmo = true;
/// <summary>
/// 是否自动开始研究(当有未完成科技时)
/// </summary>
public bool autoStartResearch = true;
/// <summary>
/// 所需研究标签页(默认为阿拉克涅科技标签页)
/// </summary>
public ResearchTabDef requiredResearchTab = null; // 将在PostLoad中设置默认值
/// <summary>
/// 每秒研究的点数(基础值,会乘以智力等级)
/// </summary>
public float baseResearchPointsPerSecond = 1.0f;
/// <summary>
/// 是否使用灵能科研点如果为true需要Comp_SwarmSpellHolder
/// </summary>
public bool usePsychicResearchPoints = true;
/// <summary>
/// 研究完成的提示消息翻译键
/// </summary>
public string researchCompletedMessageKey = "ARA_PawnResearch_Completed";
/// <summary>
/// 研究开始的提示消息翻译键
/// </summary>
public string researchStartedMessageKey = "ARA_PawnResearch_Started";
/// <summary>
/// 灵能科研点不足的提示消息翻译键
/// </summary>
public string researchNoPointsMessageKey = "ARA_PawnResearch_NoPoints";
public CompProperties_PawnResearchBlueprintReader()
{
this.compClass = typeof(Comp_PawnResearchBlueprintReader);
}
public void PostLoad()
{
// 如果没有指定研究标签页,使用默认的阿拉克涅科技标签页
if (requiredResearchTab == null)
{
requiredResearchTab = DefDatabase<ResearchTabDef>.GetNamedSilentFail("ARA_ResearchTab");
}
}
}
}

View File

@@ -0,0 +1,849 @@
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class Comp_PawnResearchBlueprintReader : ThingComp
{
// === 字段定义 ===
/// <summary>
/// 当前研究的科技项目
/// </summary>
private ResearchProjectDef currentResearch = null;
/// <summary>
/// 是否正在研究中
/// </summary>
private bool isResearching = false;
/// <summary>
/// 灵能术法组件引用
/// </summary>
public Comp_SwarmSpellHolder spellHolder = null;
/// <summary>
/// 上次研究更新的tick数
/// </summary>
private int lastResearchTick = -1;
/// <summary>
/// 研究进度已添加到ResearchManager中的进度
/// </summary>
private float currentProgress = 0f;
/// <summary>
/// 研究开始时间游戏内ticks
/// </summary>
private int researchStartTick = -1;
/// <summary>
/// 临时存储的研究点数(用于累积小数)
/// </summary>
private float accumulatedResearchPoints = 0f;
// === 属性 ===
public CompProperties_PawnResearchBlueprintReader Props =>
(CompProperties_PawnResearchBlueprintReader)this.props;
public Pawn Pawn => this.parent as Pawn;
/// <summary>
/// 当前研究的科技
/// </summary>
public ResearchProjectDef CurrentResearch
{
get => currentResearch;
private set
{
currentResearch = value;
if (currentResearch != null)
{
// 获取当前全局进度
currentProgress = Find.ResearchManager.GetProgress(currentResearch);
}
else
{
currentProgress = 0f;
}
}
}
/// <summary>
/// 当前进度
/// </summary>
public float CurrentProgress => currentProgress;
/// <summary>
/// 是否正在研究中
/// </summary>
public bool IsResearching => isResearching && currentResearch != null && !currentResearch.IsFinished;
/// <summary>
/// 研究速度(每秒点数)
/// </summary>
public float ResearchSpeedPerSecond
{
get
{
if (Pawn == null || Pawn.skills == null)
return Props.baseResearchPointsPerSecond * Props.researchSpeedMultiplier;
// 基础速度乘以智力等级
float intellectualLevel = Pawn.skills.GetSkill(SkillDefOf.Intellectual).Level;
float baseSpeed = Props.baseResearchPointsPerSecond * Props.researchSpeedMultiplier;
// 智力等级影响每级增加10%速度)
float intellectualMultiplier = 1.0f + (intellectualLevel * 0.1f);
return baseSpeed * intellectualMultiplier;
}
}
/// <summary>
/// 每秒消耗的灵能科研点
/// </summary>
public float PsychicResearchPointsPerSecond
{
get
{
// 如果不需要灵能科研点返回0
if (!Props.usePsychicResearchPoints || spellHolder == null)
return 0f;
// 每研究1点需要1点灵能科研点
return ResearchSpeedPerSecond;
}
}
/// <summary>
/// Pawn是否可以进行研究
/// </summary>
public bool CanResearch
{
get
{
if (!Props.canResearch)
return false;
if (Pawn == null || Pawn.Dead || Pawn.Downed || !Pawn.Spawned)
return false;
// 如果需要灵能科研点,检查是否有足够的灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
// 检查是否有足够的灵能科研点来支持每秒的研究
if (spellHolder.PsychicResearchPoints < PsychicResearchPointsPerSecond)
return false;
}
return true;
}
}
/// <summary>
/// 研究进度百分比0-1
/// </summary>
public float ResearchProgressPercent
{
get
{
if (currentResearch == null || currentResearch.baseCost <= 0)
return 0f;
return Mathf.Clamp01(currentProgress / currentResearch.baseCost);
}
}
/// <summary>
/// 剩余研究时间(秒)
/// </summary>
public float RemainingResearchTimeSeconds
{
get
{
if (currentResearch == null || currentResearch.baseCost <= 0 || !IsResearching)
return -1f;
float remainingPoints = currentResearch.baseCost - currentProgress;
if (ResearchSpeedPerSecond <= 0)
return -1f;
return remainingPoints / ResearchSpeedPerSecond;
}
}
// === 生命周期方法 ===
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
// 获取灵能术法组件
spellHolder = Pawn?.GetComp<Comp_SwarmSpellHolder>();
// 如果自动开始研究且当前有研究项目,开始研究
if (Props.autoStartResearch && currentResearch != null && !currentResearch.IsFinished)
{
StartResearching();
}
// 重置上次研究更新时间
lastResearchTick = Find.TickManager.TicksGame;
}
public override void CompTick()
{
base.CompTick();
// 每秒更新一次研究进度
if (Find.TickManager.TicksGame % 60 == 0)
{
UpdateResearch();
}
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Defs.Look(ref currentResearch, "currentResearch");
Scribe_Values.Look(ref isResearching, "isResearching", false);
Scribe_Values.Look(ref lastResearchTick, "lastResearchTick", -1);
Scribe_Values.Look(ref currentProgress, "currentProgress", 0f);
Scribe_Values.Look(ref researchStartTick, "researchStartTick", -1);
Scribe_Values.Look(ref accumulatedResearchPoints, "accumulatedResearchPoints", 0f);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
// 确保数据一致性
if (currentResearch == null)
{
isResearching = false;
currentProgress = 0f;
researchStartTick = -1;
accumulatedResearchPoints = 0f;
}
}
}
// === 研究逻辑方法 ===
/// <summary>
/// 开始研究新科技
/// </summary>
public void StartNewResearch(ResearchProjectDef project)
{
if (project == null)
{
return;
}
if (project.IsFinished)
{
Messages.Message("ARA_PawnResearch_AlreadyCompleted".Translate(project.LabelCap),
Pawn, MessageTypeDefOf.RejectInput);
return;
}
// 检查前置条件
if (!AreAllPrerequisitesCompleted(project))
{
Messages.Message("ARA_PawnResearch_PrerequisitesNotMet".Translate(project.LabelCap),
Pawn, MessageTypeDefOf.RejectInput);
return;
}
// 检查是否有足够的灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
float requiredPoints = project.baseCost - Find.ResearchManager.GetProgress(project);
if (!spellHolder.HasEnoughPsychicResearchPoints(requiredPoints))
{
Messages.Message(Props.researchNoPointsMessageKey.Translate(project.LabelCap),
Pawn, MessageTypeDefOf.RejectInput);
return;
}
}
// 设置当前研究
CurrentResearch = project;
// 开始研究
StartResearching();
// 发送消息
if (!Props.researchStartedMessageKey.NullOrEmpty())
{
Messages.Message(Props.researchStartedMessageKey.Translate(Pawn.LabelShortCap, project.LabelCap),
Pawn, MessageTypeDefOf.PositiveEvent);
}
ArachnaeLog.Debug($"[PawnResearch] {Pawn.LabelShort} 开始研究: {project.defName}");
}
/// <summary>
/// 开始研究(内部方法)
/// </summary>
private void StartResearching()
{
if (currentResearch == null || currentResearch.IsFinished)
{
isResearching = false;
return;
}
isResearching = true;
researchStartTick = Find.TickManager.TicksGame;
lastResearchTick = researchStartTick;
// 获取当前全局进度
currentProgress = Find.ResearchManager.GetProgress(currentResearch);
ArachnaeLog.Debug($"[PawnResearch] {Pawn?.LabelShort} 开始研究中: {currentResearch.defName}");
}
/// <summary>
/// 停止研究
/// </summary>
public void StopResearching()
{
isResearching = false;
researchStartTick = -1;
ArachnaeLog.Debug($"[PawnResearch] {Pawn?.LabelShort} 停止研究");
}
/// <summary>
/// 更新研究进度
/// </summary>
private void UpdateResearch()
{
if (!IsResearching || !CanResearch)
{
// 如果不能研究,停止研究
if (isResearching)
{
StopResearching();
}
return;
}
try
{
// 计算本次应该研究多少点
float researchPoints = ResearchSpeedPerSecond;
accumulatedResearchPoints += researchPoints;
// 如果累积的研究点数大于等于1则添加到全局进度
if (accumulatedResearchPoints >= 1.0f)
{
int pointsToAdd = Mathf.FloorToInt(accumulatedResearchPoints);
// 消耗灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
if (!spellHolder.ConsumePsychicResearchPoints(pointsToAdd, $"研究 {currentResearch.LabelCap}"))
{
// 灵能科研点不足,停止研究
StopResearching();
Messages.Message(Props.researchNoPointsMessageKey.Translate(currentResearch.LabelCap),
Pawn, MessageTypeDefOf.NegativeEvent);
return;
}
}
// 添加到全局研究进度
AddResearchProgress(pointsToAdd);
// 减去已添加的点数
accumulatedResearchPoints -= pointsToAdd;
}
// 检查是否完成
CheckResearchCompletion();
// 更新上次研究时间
lastResearchTick = Find.TickManager.TicksGame;
}
catch (Exception ex)
{
ArachnaeLog.Debug($"[PawnResearch] 更新研究进度时出错: {ex.Message}");
StopResearching();
}
}
/// <summary>
/// 添加研究进度到全局
/// </summary>
private void AddResearchProgress(float points)
{
if (currentResearch == null || currentResearch.IsFinished || points <= 0)
return;
// 获取当前全局进度
float globalProgress = Find.ResearchManager.GetProgress(currentResearch);
float remaining = currentResearch.baseCost - globalProgress;
// 确保不会超过总需求
float pointsToAdd = Mathf.Min(points, remaining);
if (pointsToAdd > 0)
{
Find.ResearchManager.AddProgress(currentResearch, pointsToAdd);
// 更新本地进度
currentProgress = Find.ResearchManager.GetProgress(currentResearch);
}
}
/// <summary>
/// 检查研究是否完成
/// </summary>
private void CheckResearchCompletion()
{
if (currentResearch == null)
return;
if (currentResearch.IsFinished)
{
// 研究完成
OnResearchCompleted();
}
}
/// <summary>
/// 研究完成时的处理
/// </summary>
private void OnResearchCompleted()
{
if (currentResearch == null)
return;
// 发送完成消息
if (!Props.researchCompletedMessageKey.NullOrEmpty())
{
Messages.Message(Props.researchCompletedMessageKey.Translate(Pawn.LabelShortCap, currentResearch.LabelCap),
Pawn, MessageTypeDefOf.PositiveEvent);
}
ArachnaeLog.Debug($"[PawnResearch] {Pawn.LabelShort} 完成研究: {currentResearch.defName}");
// 停止研究
StopResearching();
// 清空当前研究
CurrentResearch = null;
currentProgress = 0f;
accumulatedResearchPoints = 0f;
}
/// <summary>
/// 强制完成当前研究(调试用)
/// </summary>
public void ForceCompleteResearch()
{
if (currentResearch == null || currentResearch.IsFinished)
return;
// 消耗剩余的灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
float remainingPoints = currentResearch.baseCost - Find.ResearchManager.GetProgress(currentResearch);
spellHolder.ConsumePsychicResearchPoints(remainingPoints, $"强制完成研究 {currentResearch.LabelCap}");
}
// 直接完成研究
Find.ResearchManager.FinishProject(currentResearch, false);
OnResearchCompleted();
}
// === 条件检查方法 ===
/// <summary>
/// 检查所有前置条件是否完成
/// </summary>
private bool AreAllPrerequisitesCompleted(ResearchProjectDef project)
{
if (project == null)
return false;
// 检查普通前置
if (project.prerequisites != null)
{
foreach (var prereq in project.prerequisites)
{
if (!prereq.IsFinished)
return false;
}
}
// 检查隐藏前置
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
return false;
}
}
return true;
}
private bool HasMissingHiddenPrerequisites(ResearchProjectDef project)
{
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
return true;
}
}
return false;
}
// === Gizmo 和 UI 方法 ===
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (Gizmo gizmo in base.CompGetGizmosExtra())
{
yield return gizmo;
}
if (!Props.showResearchGizmo || Pawn == null || Pawn.Faction != Faction.OfPlayer)
yield break;
// 研究进度 Gizmo
yield return new Gizmo_PawnResearchProgress(this);
// 选择研究按钮
if (CanResearch || currentResearch == null)
{
var selectCmd = new Command_Action();
selectCmd.defaultLabel = "ARA_PawnResearch_SelectProject".Translate();
selectCmd.defaultDesc = "ARA_PawnResearch_SelectProjectDesc".Translate();
selectCmd.icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Abilities/ARA_EggSpew_Techprint", false);
selectCmd.action = delegate
{
ShowResearchMenu();
};
yield return selectCmd;
}
// 开始/停止研究按钮
if (currentResearch != null && !currentResearch.IsFinished)
{
if (IsResearching)
{
var stopCmd = new Command_Action();
stopCmd.defaultLabel = "ARA_PawnResearch_StopResearch".Translate();
stopCmd.defaultDesc = "ARA_PawnResearch_StopResearchDesc".Translate();
stopCmd.icon = ContentFinder<Texture2D>.Get("UI/Commands/Halt", false);
stopCmd.action = delegate
{
StopResearching();
Messages.Message("ARA_PawnResearch_Stopped".Translate(Pawn.LabelShortCap, currentResearch.LabelCap),
Pawn, MessageTypeDefOf.NeutralEvent);
};
yield return stopCmd;
}
else
{
var startCmd = new Command_Action();
startCmd.defaultLabel = "ARA_PawnResearch_StartResearch".Translate();
startCmd.defaultDesc = "ARA_PawnResearch_StartResearchDesc".Translate();
startCmd.icon = ContentFinder<Texture2D>.Get("UI/Commands/Play", false);
startCmd.action = delegate
{
StartResearching();
Messages.Message("ARA_PawnResearch_Started".Translate(Pawn.LabelShortCap, currentResearch.LabelCap),
Pawn, MessageTypeDefOf.PositiveEvent);
};
yield return startCmd;
}
}
// 调试按钮
if (DebugSettings.godMode && currentResearch != null && !currentResearch.IsFinished)
{
var debugCmd = new Command_Action();
debugCmd.defaultLabel = "ARA_PawnResearch_DebugComplete".Translate();
debugCmd.defaultDesc = "ARA_PawnResearch_DebugCompleteDesc".Translate();
debugCmd.icon = ContentFinder<Texture2D>.Get("UI/Designators/Dev", false);
debugCmd.action = delegate
{
ForceCompleteResearch();
};
yield return debugCmd;
}
}
/// <summary>
/// 显示研究选择菜单
/// </summary>
public void ShowResearchMenu()
{
try
{
// 使用指定的研究标签页
ResearchTabDef researchTab = Props.requiredResearchTab;
if (researchTab == null)
{
// 如果没有指定,使用默认的阿拉克涅科技标签页
researchTab = DefDatabase<ResearchTabDef>.GetNamedSilentFail("ARA_ResearchTab");
if (researchTab == null)
{
Messages.Message("ARA_PawnResearch_TabNotFound".Translate(), MessageTypeDefOf.RejectInput);
return;
}
}
// 获取可用的研究项目
var availableProjects = DefDatabase<ResearchProjectDef>.AllDefsListForReading
.Where(p => p.tab == researchTab && p.techprintCount > 0 && !p.IsFinished)
.ToList();
if (availableProjects.Count == 0)
{
Messages.Message("ARA_PawnResearch_NoProjectsAvailable".Translate(), MessageTypeDefOf.NeutralEvent);
return;
}
// 创建菜单选项
List<FloatMenuOption> options = new List<FloatMenuOption>();
var sortedProjects = availableProjects.OrderBy(p => p.defName).ToList();
foreach (var project in sortedProjects)
{
bool allPrerequisitesMet = AreAllPrerequisitesCompleted(project);
// 检查是否有足够的灵能科研点
bool hasEnoughPoints = true;
if (Props.usePsychicResearchPoints && spellHolder != null)
{
float requiredPoints = project.baseCost - Find.ResearchManager.GetProgress(project);
hasEnoughPoints = spellHolder.HasEnoughPsychicResearchPoints(requiredPoints);
}
string label = project.LabelCap.RawText ?? project.defName;
float globalProgress = Find.ResearchManager.GetProgress(project);
// 显示进度
if (globalProgress > 0)
label += $" ({globalProgress:F0}/{project.baseCost:F0})";
// 显示所需灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
float requiredPoints = project.baseCost - globalProgress;
label += $" [{requiredPoints:F0}点]";
}
// 根据条件设置颜色
if (!allPrerequisitesMet)
{
bool missingHidden = HasMissingHiddenPrerequisites(project);
if (missingHidden)
label = $"<color=#ff9900>{label} [{"ARA_PawnResearch_HiddenPrerequisite".Translate()}]</color>";
else
label = $"<color=#999999>{label} [{"ARA_PawnResearch_PrerequisitesNeeded".Translate()}]</color>";
}
else if (!hasEnoughPoints)
{
label = $"<color=#ff6666>{label} [{"ARA_PawnResearch_InsufficientPoints".Translate()}]</color>";
}
// 创建菜单选项
var option = new FloatMenuOption(label, () => StartNewResearch(project))
{
Disabled = !allPrerequisitesMet || !hasEnoughPoints,
tooltip = GetProjectTooltip(project, allPrerequisitesMet, hasEnoughPoints)
};
options.Add(option);
}
if (options.Count > 0)
{
Find.WindowStack.Add(new FloatMenu(options));
}
}
catch (Exception ex)
{
ArachnaeLog.Debug($"[PawnResearch] Error in ShowResearchMenu: {ex}");
Messages.Message("ARA_PawnResearch_MenuError".Translate(ex.Message),
MessageTypeDefOf.NegativeEvent);
}
}
/// <summary>
/// 获取研究项目的工具提示
/// </summary>
private string GetProjectTooltip(ResearchProjectDef project, bool prerequisitesMet, bool hasEnoughPoints)
{
var builder = new System.Text.StringBuilder();
builder.AppendLine(project.description.StripTags());
builder.AppendLine();
builder.AppendLine("ARA_PawnResearch_ProjectCost".Translate() + $": {project.baseCost}");
builder.AppendLine("ARA_PawnResearch_BlueprintCount".Translate() + $": {project.techprintCount}");
float globalProgress = Find.ResearchManager.GetProgress(project);
builder.AppendLine("ARA_PawnResearch_CurrentProgress".Translate() + $": {globalProgress:F0}/{project.baseCost:F0}");
// 显示所需灵能科研点
if (Props.usePsychicResearchPoints && spellHolder != null)
{
float requiredPoints = project.baseCost - globalProgress;
builder.AppendLine("ARA_PawnResearch_RequiredPoints".Translate() + $": {requiredPoints:F0}");
builder.AppendLine("ARA_PawnResearch_CurrentPoints".Translate() + $": {spellHolder.PsychicResearchPoints:F0}");
}
// 显示研究速度
builder.AppendLine("ARA_PawnResearch_Speed".Translate() + $": {ResearchSpeedPerSecond:F1}/秒");
// 显示研究时间估算
if (prerequisitesMet && hasEnoughPoints)
{
float remainingPoints = project.baseCost - globalProgress;
float timeSeconds = remainingPoints / ResearchSpeedPerSecond;
int ticks = Mathf.RoundToInt(timeSeconds * 60f);
string timeStr = ticks.ToStringTicksToPeriod(allowSeconds: true, shortForm: true);
builder.AppendLine("ARA_PawnResearch_EstimatedTime".Translate() + $": {timeStr}");
}
// 检查未完成的前置
if (!prerequisitesMet)
{
List<ResearchProjectDef> missingPrereqs = new List<ResearchProjectDef>();
// 普通前置
if (project.prerequisites != null)
{
foreach (var prereq in project.prerequisites)
{
if (!prereq.IsFinished)
missingPrereqs.Add(prereq);
}
}
// 隐藏前置
if (project.hiddenPrerequisites != null)
{
foreach (var hiddenPrereq in project.hiddenPrerequisites)
{
if (hiddenPrereq != null && !hiddenPrereq.IsFinished)
missingPrereqs.Add(hiddenPrereq);
}
}
if (missingPrereqs.Count > 0)
{
builder.AppendLine();
builder.AppendLine("<color=#ff9999>" + "ARA_PawnResearch_MissingPrerequisites".Translate() + ":</color>");
foreach (var prereq in missingPrereqs)
{
string label = prereq.LabelCap.RawText ?? prereq.defName;
bool isHidden = project.hiddenPrerequisites != null &&
project.hiddenPrerequisites.Contains(prereq);
if (isHidden)
builder.AppendLine($" • {label} <color=#ffcc00>[{"ARA_PawnResearch_MissingHiddenPrerequisites".Translate()}]</color>");
else
builder.AppendLine($" • {label}");
}
}
}
// 检查灵能科研点是否足够
if (!hasEnoughPoints && Props.usePsychicResearchPoints && spellHolder != null)
{
float requiredPoints = project.baseCost - globalProgress;
builder.AppendLine();
builder.AppendLine("<color=#ff6666>" + "ARA_PawnResearch_InsufficientPoints".Translate() + ":</color>");
builder.AppendLine($" • {"ARA_PawnResearch_Required".Translate()}: {requiredPoints:F0}");
builder.AppendLine($" • {"ARA_PawnResearch_Available".Translate()}: {spellHolder.PsychicResearchPoints:F0}");
}
return builder.ToString();
}
// === 调试和信息方法 ===
/// <summary>
/// 获取研究状态描述
/// </summary>
public string GetResearchStatus()
{
if (Pawn == null)
return "无Pawn";
if (currentResearch == null)
return $"{Pawn.LabelShort}: 未选择研究项目";
if (currentResearch.IsFinished)
return $"{Pawn.LabelShort}: 已完成研究 {currentResearch.LabelCap}";
string status = IsResearching ? "研究中" : "暂停中";
string progress = $"{currentProgress:F0}/{currentResearch.baseCost:F0} ({ResearchProgressPercent:P0})";
string pointsInfo = "";
if (Props.usePsychicResearchPoints && spellHolder != null)
{
pointsInfo = $", 灵能科研点: {spellHolder.PsychicResearchPoints:F0}";
}
return $"{Pawn.LabelShort}: {status} {currentResearch.LabelCap} ({progress}{pointsInfo})";
}
/// <summary>
/// 获取调试信息
/// </summary>
public string GetDebugInfo()
{
var builder = new System.Text.StringBuilder();
builder.AppendLine("=== Pawn研究蓝图解读器调试信息 ===");
builder.AppendLine($"Pawn: {Pawn?.LabelShort ?? ""}");
builder.AppendLine($"可研究: {CanResearch}");
builder.AppendLine($"正在研究: {IsResearching}");
if (currentResearch != null)
{
builder.AppendLine($"当前研究: {currentResearch.defName}");
builder.AppendLine($"研究进度: {currentProgress:F0}/{currentResearch.baseCost:F0} ({ResearchProgressPercent:P0})");
builder.AppendLine($"研究速度: {ResearchSpeedPerSecond:F1}/秒");
}
else
{
builder.AppendLine("当前研究: 无");
}
if (spellHolder != null)
{
builder.AppendLine($"灵能术法组件: 已连接");
builder.AppendLine($"灵能科研点: {spellHolder.PsychicResearchPoints:F0}");
builder.AppendLine($"每秒消耗: {PsychicResearchPointsPerSecond:F1}");
}
else
{
builder.AppendLine($"灵能术法组件: 未找到");
}
builder.AppendLine($"使用灵能科研点: {Props.usePsychicResearchPoints}");
builder.AppendLine($"自动开始研究: {Props.autoStartResearch}");
builder.AppendLine($"研究标签页: {Props.requiredResearchTab?.defName ?? ""}");
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,274 @@
using RimWorld;
using System.Text;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
[StaticConstructorOnStartup]
public class Gizmo_PawnResearchProgress : Gizmo
{
private readonly Comp_PawnResearchBlueprintReader researchComp;
// 尺寸常量
private const float Width = 180f;
private const float GizmoHeight = 75f;
private const float Padding = 6f;
private const float BarHeight = 18f;
// 材质颜色
private static readonly Texture2D ProgressBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.3f, 0.6f, 0.9f, 0.9f));
private static readonly Texture2D CompletedBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.3f, 0.9f));
private static readonly Texture2D PausedBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.7f, 0.7f, 0.3f, 0.9f));
private static readonly Texture2D NoPowerBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.5f, 0.5f, 0.5f, 0.9f));
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.15f, 0.15f, 0.15f, 0.8f));
public Gizmo_PawnResearchProgress(Comp_PawnResearchBlueprintReader researchComp)
{
this.researchComp = researchComp;
Order = -130f;
}
public override float GetWidth(float maxWidth)
{
return Mathf.Min(Width, maxWidth);
}
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
{
Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), GizmoHeight);
Widgets.DrawWindowBackground(rect);
Rect innerRect = rect.ContractedBy(Padding);
float curY = innerRect.y;
var currentResearch = researchComp.CurrentResearch;
// === 第一行:标题(可点击选择研究) ===
Text.Font = GameFont.Small;
Text.Anchor = TextAnchor.MiddleLeft;
Rect titleRect = new Rect(innerRect.x, curY, innerRect.width, 18f);
string title;
if (currentResearch != null)
{
title = currentResearch.LabelCap.RawText ?? currentResearch.defName;
// 截断过长的标题
title = title.Truncate(innerRect.width - 20f);
}
else
{
title = "ARA_PawnResearch_NoProject".Translate();
}
// 标题可点击
if (Mouse.IsOver(titleRect))
{
Widgets.DrawHighlight(titleRect);
}
if (Widgets.ButtonInvisible(titleRect) && researchComp.CanResearch)
{
researchComp.ShowResearchMenu();
}
// 显示下拉箭头(如果可以选择研究)
if (researchComp.CanResearch)
{
GUI.color = new Color(0.7f, 0.9f, 1f);
Widgets.Label(titleRect, title + " ▼");
GUI.color = Color.white;
}
else
{
Widgets.Label(titleRect, title);
}
curY += 20f;
// === 第二行:状态信息 ===
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleLeft;
Rect statusRect = new Rect(innerRect.x, curY, innerRect.width, 14f);
if (currentResearch != null)
{
string statusText;
if (currentResearch.IsFinished)
{
GUI.color = new Color(0.3f, 0.9f, 0.3f);
statusText = "ARA_PawnResearch_Completed".Translate();
}
else if (researchComp.IsResearching && researchComp.CanResearch)
{
GUI.color = new Color(0.5f, 0.8f, 1f);
statusText = "ARA_PawnResearch_Researching".Translate();
}
else if (!researchComp.CanResearch)
{
GUI.color = new Color(0.8f, 0.2f, 0.2f);
statusText = "ARA_PawnResearch_CannotResearch".Translate();
}
else
{
GUI.color = new Color(0.9f, 0.7f, 0.2f);
statusText = "ARA_PawnResearch_Paused".Translate();
}
Widgets.Label(statusRect, statusText);
}
else
{
GUI.color = new Color(0.5f, 0.5f, 0.5f);
Widgets.Label(statusRect, "ARA_PawnResearch_SelectProject".Translate());
}
curY += 15f;
// === 第三行:进度条 ===
GUI.color = Color.white;
Rect barRect = new Rect(innerRect.x, curY, innerRect.width, BarHeight);
// 背景
GUI.DrawTexture(barRect, EmptyBarTex);
if (currentResearch != null)
{
float percentage = researchComp.ResearchProgressPercent;
// 根据状态选择颜色
Texture2D barTex;
if (currentResearch.IsFinished)
barTex = CompletedBarTex;
else if (researchComp.IsResearching && researchComp.CanResearch)
barTex = ProgressBarTex;
else if (!researchComp.CanResearch)
barTex = NoPowerBarTex;
else
barTex = PausedBarTex;
// 填充条
Rect fillRect = new Rect(barRect.x, barRect.y, barRect.width * percentage, barRect.height);
GUI.DrawTexture(fillRect, barTex);
// 百分比文字
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
string progressText;
if (currentResearch.IsFinished)
{
progressText = "ARA_PawnResearch_CompletedShort".Translate();
}
else
{
progressText = $"{researchComp.CurrentProgress:F0} / {currentResearch.baseCost:F0}";
}
Widgets.Label(barRect, progressText);
}
else
{
// 无项目时显示空状态
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = new Color(0.5f, 0.5f, 0.5f);
Widgets.Label(barRect, "---");
}
// === 工具提示 ===
if (Mouse.IsOver(rect))
{
Widgets.DrawHighlight(rect);
TooltipHandler.TipRegion(rect, GetTooltip());
}
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Small;
return new GizmoResult(GizmoState.Clear);
}
private string GetTooltip()
{
var sb = new System.Text.StringBuilder();
var currentResearch = researchComp.CurrentResearch;
sb.AppendLine("ARA_PawnResearch_TooltipTitle".Translate());
sb.AppendLine();
if (currentResearch != null)
{
sb.AppendLine("ARA_PawnResearch_TooltipProject".Translate(currentResearch.LabelCap));
sb.AppendLine("ARA_PawnResearch_TooltipProgress".Translate(
researchComp.CurrentProgress.ToString("F0"),
currentResearch.baseCost.ToString("F0")));
sb.AppendLine("ARA_PawnResearch_TooltipPercentage".Translate(researchComp.ResearchProgressPercent.ToStringPercent()));
sb.AppendLine();
if (currentResearch.IsFinished)
{
sb.AppendLine("<color=green>" + "ARA_PawnResearch_TooltipCompleted".Translate() + "</color>");
}
else if (researchComp.IsResearching && researchComp.CanResearch)
{
// 显示研究速度
sb.AppendLine("ARA_PawnResearch_TooltipSpeed".Translate(researchComp.ResearchSpeedPerSecond.ToString("F1")));
// 显示灵能科研点消耗
if (researchComp.Props.usePsychicResearchPoints)
{
sb.AppendLine("ARA_PawnResearch_TooltipPointsConsumption".Translate(researchComp.PsychicResearchPointsPerSecond.ToString("F1")));
}
}
else if (!researchComp.CanResearch)
{
sb.AppendLine("<color=red>" + "ARA_PawnResearch_TooltipCannotResearch".Translate() + "</color>");
sb.AppendLine("ARA_PawnResearch_TooltipCannotResearchReason".Translate());
// 检查具体原因
if (researchComp.Pawn != null)
{
if (researchComp.Pawn.Dead)
sb.AppendLine(" • " + "Dead".Translate());
if (researchComp.Pawn.Downed)
sb.AppendLine(" • " + "Downed".Translate());
if (!researchComp.Pawn.Spawned)
sb.AppendLine(" • " + "NotSpawned".Translate());
}
if (researchComp.Props.usePsychicResearchPoints && researchComp.spellHolder != null)
{
if (researchComp.spellHolder.PsychicResearchPoints < researchComp.PsychicResearchPointsPerSecond)
{
sb.AppendLine(" • " + "ARA_PawnResearch_InsufficientPointsShort".Translate());
}
}
}
else
{
sb.AppendLine("<color=yellow>" + "ARA_PawnResearch_TooltipPaused".Translate() + "</color>");
}
}
else
{
sb.AppendLine("ARA_PawnResearch_TooltipNoProject".Translate());
}
// 显示Pawn信息
if (researchComp.Pawn != null)
{
sb.AppendLine();
sb.AppendLine("ARA_PawnResearch_TooltipPawnInfo".Translate());
sb.AppendLine($" • {"Intellectual".Translate()}: {researchComp.Pawn.skills.GetSkill(SkillDefOf.Intellectual).Level}");
if (researchComp.spellHolder != null)
{
sb.AppendLine($" • {"ARA_PawnResearch_PsychicPoints".Translate()}: {researchComp.spellHolder.PsychicResearchPoints:F0}");
}
}
return sb.ToString().TrimEndNewlines();
}
}
}