11
This commit is contained in:
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -297,6 +297,9 @@
|
||||
<def>CrumblingMind</def>
|
||||
<severity>0.01</severity>
|
||||
</li>
|
||||
<li>
|
||||
<def>ARA_NonPlayer_HiveMindDroneHediff</def>
|
||||
</li>
|
||||
</startingHediffs>
|
||||
</PawnKindDef>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Binary file not shown.
@@ -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",
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user