diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 20218a0..008ca40 100644
Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ
diff --git a/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml b/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
index f5435fc..6352e85 100644
--- a/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
+++ b/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
@@ -587,600 +587,6 @@
-
- ArachnaeQueen_Neurotyrant_Body
-
-
- Torso
- Middle
- Outside
-
- Torso
-
-
-
-
- ARA_Dorsum
- 0.14
-
- Torso
-
-
-
-
- ARA_Chitin_Shell
- 背部甲片
- 0.02
- Outside
-
- Torso
-
-
-
-
- ARA_Exoskeleton_Dorsum
- 0.016
- Inside
-
- Torso
-
-
-
-
-
-
- ARA_Sternum
- 0.15
-
- Torso
-
-
-
-
- ARA_Exoskeleton_Sternum
- 0.015
- Outside
-
- Torso
-
-
-
-
- Heart
- 0.020
- Inside
-
- Torso
-
-
-
-
- Stomach
- 0.025
- Inside
-
- Torso
-
-
-
-
- Lung
- 左肺(其一)
- 0.025
- Inside
-
- Torso
-
-
-
- Lung
- 左肺(其二)
- 0.025
- Inside
-
- Torso
-
-
-
- Lung
- 右肺(其一)
- 0.025
- Inside
-
- Torso
-
-
-
- Lung
- 右肺(其二)
- 0.025
- Inside
-
- Torso
-
-
-
-
- Kidney
- 左肾
- 0.017
- Inside
-
- Torso
-
-
-
- Kidney
- 右肾
- 0.017
- Inside
-
- Torso
-
-
-
-
- Liver
- 0.025
- 肝脏(其一)
- Inside
-
- Torso
-
-
-
- Liver
- 肝脏(其二)
- 0.025
- Inside
-
- Torso
-
-
-
-
-
-
- ARA_Tail
- Bottom
- Inside
- 0.15
-
- Torso
-
-
-
-
- ARA_Chitin_Shell
- 尾部甲片
- 0.01
- Outside
-
- Torso
-
-
-
-
- ARA_Gonad
- 0.005
- Inside
-
- ARA_Genitalias
-
-
-
-
- ARA_Ovary
- 0.01
- Inside
-
- ARA_Genitalias
-
-
-
-
-
-
- Neck
- 0.075
- Top
-
- Neck
-
-
-
- Head
- 0.80
-
- UpperHead
- FullHead
- HeadAttackTool
-
-
-
-
- ARA_Chitin_Shell
- 头部甲片
- 0.02
- Outside
-
- UpperHead
-
-
-
-
- ARA_Psy_Nerve_Tract
- 第一神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第二神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第三神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第四神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第四神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第五神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第六四神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第七神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
- ARA_Psy_Nerve_Tract
- 第八神经束
- 0.05
- Inside
-
- ARA_Psy_Nerve_Tracts
-
-
-
-
- Skull
- 0.18
- Inside
-
- UpperHead
- Eyes
- FullHead
-
-
-
- Brain
- 0.8
-
- UpperHead
- Eyes
- FullHead
-
-
-
-
-
- Eye
- left eye
- 0.07
-
- FullHead
- Eyes
-
- LeftEye
- true
-
- South
- West
-
-
-
- Eye
- right eye
- 0.07
-
- FullHead
- Eyes
-
- RightEye
-
- South
- East
-
-
-
- Ear
- left ear
- 0.07
- true
-
- UpperHead
- FullHead
-
-
-
- Ear
- right ear
- 0.07
-
- UpperHead
- FullHead
-
-
-
- Nose
- 0.10
-
- FullHead
-
-
-
- Jaw
- 0.15
-
- Teeth
- FullHead
- Mouth
-
-
-
- Tongue
- 0.001
- Inside
-
- FullHead
-
-
-
-
-
-
-
-
-
-
- Shoulder
- 左副肢关节
- 0.12
- LeftShoulder
- true
-
- Shoulders
-
-
-
- Clavicle
- 左副肢外骨骼
- 0.09
- Top
- Outside
- true
-
- Shoulders
-
-
-
- Arm
- 左副肢
- 0.77
- true
-
- Arms
-
-
-
- Hand
- 左鳌钳
- 0.14
- Bottom
- true
-
- Hands
- HeadClaw
-
-
-
- Finger
- 右鳌钳口
- 0.14
-
- Hands
- LeftHand
-
-
-
-
-
-
-
-
-
- Shoulder
- 右副肢关节
- 0.12
- LeftShoulder
- true
-
- Shoulders
-
-
-
- Clavicle
- 右副肢外骨骼
- 0.09
- Top
- Outside
- true
-
- Shoulders
-
-
-
- Arm
- 右副肢
- 0.77
- true
-
- Arms
-
-
-
- Hand
- 右鳌钳
- 0.14
- Bottom
- true
-
- Hands
- HeadClaw
-
-
-
- Finger
- 右鳌钳口
- 0.14
-
- Hands
- RightHand
-
-
-
-
-
-
-
-
-
-
- Waist
- 体节分界
- 0
- Bottom
-
- Waist
-
-
-
- Leg
- 左肢
- 0.06
- Bottom
-
- Legs
-
- LeftLeg
- true
-
-
-
- ARA_Chitin_Shell
- 左肢甲片
- 0.02
- Outside
-
- Legs
-
-
-
-
- Femur
- 左肢外骨骼
- 0.1
- Inside
-
- Legs
-
-
-
-
-
- Leg
- 右肢
- 0.06
- Bottom
-
- Legs
-
- LeftLeg
- true
-
-
-
- ARA_Chitin_Shell
- 右肢甲片
- 0.02
- Outside
-
- Legs
-
-
-
-
- Femur
- 右肢外骨骼
- 0.1
- Inside
-
- Legs
-
-
-
-
-
-
-
ARA_Dorsum
diff --git a/1.6/1.6/Defs/Stats/ARA_Stats.xml b/1.6/1.6/Defs/Stats/ARA_Stats.xml
index 874b248..49fdf78 100644
--- a/1.6/1.6/Defs/Stats/ARA_Stats.xml
+++ b/1.6/1.6/Defs/Stats/ARA_Stats.xml
@@ -100,18 +100,6 @@
2201
false
-
- ARA_SwarmSpell_Cooldown_Delay
-
- 当阿拉克涅灵吸种使用虫群灵能能力时,产生的灵能负荷会在此时间后开始逐渐下降,任何施术都会重置冷却时间。
- Basics
- 0
- Integer
- 0
- 0
- 2201
- false
-
ARA_SwarmSpell_Level
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 9fc5e57..3cd63b2 100644
Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
index 4f7488c..38476c3 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -3,100 +3,8 @@
"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\\hediffs\\hediffcomp_reflectmeleedamage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\hediffcomp_reflectmeleedamage.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\\ara_defof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:ara_defof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_supercarry\\jobdriver_supercarry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_supercarry\\jobdriver_supercarry.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_swarmmaintain\\jobdriver_swarmmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_swarmmaintain\\jobdriver_swarmmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_swarmmaintain\\jobgiver_swarmmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_swarmmaintain\\jobgiver_swarmmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_swarmmaintain\\thinknode_conditionalshouldmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_swarmmaintain\\thinknode_conditionalshouldmaintain.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\\damage\\damageworker_explosionwithterrain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:damage\\damageworker_explosionwithterrain.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\\damage\\damagedefextension_terraincover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:damage\\damagedefextension_terraincover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_feedwithhoney\\jobdriver_feedwithhoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_feedwithhoney\\jobdriver_feedwithhoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_extracthoney\\jobgiver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_extracthoney\\jobgiver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\jobs\\jobdriver_extracthoney\\jobdriver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_extracthoney\\jobdriver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\compabilityeffect_toggledroppodintercept.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_toggledroppodintercept.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\\flyover\\gamecomponent_droppodinterceptor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\gamecomponent_droppodinterceptor.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\\flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\hediffs\\ara_gestaltnode\\hediffcomp_gestaltnode.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\hediffcomp_gestaltnode.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|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\\abilities\\ara_fanshapedstunknockback\\compabilityeffect_fanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_fanshapedstunknockback\\compabilityeffect_fanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_fanshapedstunknockback\\compproperties_abilityfanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_fanshapedstunknockback\\compproperties_abilityfanshapedstunknockback.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\\researchblueprintreadermanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_researchblueprintreader\\researchblueprintreadermanager.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\\abilities\\ara_ejectorgans\\compabilityeffect_ejectorgans.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_ejectorgans\\compabilityeffect_ejectorgans.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\\compproperties_hediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_comphediffgiver\\compproperties_hediffgiver.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\\arachnaelog.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:arachnaelog.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -106,300 +14,24 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 2,
+ "SelectedChildIndex": 1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
- {
- "$type": "Document",
- "DocumentIndex": 1,
- "Title": "ARA_DefOf.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
- "RelativeDocumentMoniker": "ARA_DefOf.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
- "RelativeToolTip": "ARA_DefOf.cs",
- "ViewState": "AgIAAFQAAAAAAAAAAAAUwGcAAAAmAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-24T08:34:43.383Z"
- },
{
"$type": "Document",
"DocumentIndex": 0,
- "Title": "HediffComp_ReflectMeleeDamage.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\HediffComp_ReflectMeleeDamage.cs",
- "RelativeDocumentMoniker": "Hediffs\\HediffComp_ReflectMeleeDamage.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\HediffComp_ReflectMeleeDamage.cs",
- "RelativeToolTip": "Hediffs\\HediffComp_ReflectMeleeDamage.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAAoAAAAAAAAAA==",
+ "Title": "ArachnaeLog.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ArachnaeLog.cs",
+ "RelativeDocumentMoniker": "ArachnaeLog.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ArachnaeLog.cs",
+ "RelativeToolTip": "ArachnaeLog.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAwAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-24T08:33:52.75Z",
+ "WhenOpened": "2026-03-26T06:10:50.583Z",
"EditorCaption": ""
- },
- {
- "$type": "Document",
- "DocumentIndex": 2,
- "Title": "JobDriver_SuperCarry.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SuperCarry\\JobDriver_SuperCarry.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_SuperCarry\\JobDriver_SuperCarry.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SuperCarry\\JobDriver_SuperCarry.cs",
- "RelativeToolTip": "Jobs\\JobDriver_SuperCarry\\JobDriver_SuperCarry.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAA3AAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T03:21:58.524Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 3,
- "Title": "JobDriver_SwarmMaintain.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
- "RelativeToolTip": "Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAAAXAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T03:21:31.585Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 4,
- "Title": "JobGiver_SwarmMaintain.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobGiver_SwarmMaintain.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_SwarmMaintain\\JobGiver_SwarmMaintain.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobGiver_SwarmMaintain.cs",
- "RelativeToolTip": "Jobs\\JobDriver_SwarmMaintain\\JobGiver_SwarmMaintain.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T03:21:34.528Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 5,
- "Title": "ThinkNode_ConditionalShouldMaintain.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\ThinkNode_ConditionalShouldMaintain.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_SwarmMaintain\\ThinkNode_ConditionalShouldMaintain.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\ThinkNode_ConditionalShouldMaintain.cs",
- "RelativeToolTip": "Jobs\\JobDriver_SwarmMaintain\\ThinkNode_ConditionalShouldMaintain.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T03:21:32.052Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 6,
- "Title": "DamageWorker_ExplosionWithTerrain.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Damage\\DamageWorker_ExplosionWithTerrain.cs",
- "RelativeDocumentMoniker": "Damage\\DamageWorker_ExplosionWithTerrain.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Damage\\DamageWorker_ExplosionWithTerrain.cs",
- "RelativeToolTip": "Damage\\DamageWorker_ExplosionWithTerrain.cs",
- "ViewState": "AgIAAA0AAAAAAAAAAAAQwB4AAAARAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T01:33:29.803Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 7,
- "Title": "DamageDefExtension_TerrainCover.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Damage\\DamageDefExtension_TerrainCover.cs",
- "RelativeDocumentMoniker": "Damage\\DamageDefExtension_TerrainCover.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Damage\\DamageDefExtension_TerrainCover.cs",
- "RelativeToolTip": "Damage\\DamageDefExtension_TerrainCover.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAACQAAAAYAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-06T01:33:24.976Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 8,
- "Title": "JobDriver_StripChitin.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
- "RelativeToolTip": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAADwvyEAAAAQAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-03T15:51:49.621Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 9,
- "Title": "JobDriver_FeedWithHoney.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
- "RelativeToolTip": "Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAADwvyUAAAAfAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-03T15:51:26.648Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 10,
- "Title": "JobGiver_ExtractHoney.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobGiver_ExtractHoney.cs",
- "RelativeDocumentMoniker": "Jobs\\JobDriver_ExtractHoney\\JobGiver_ExtractHoney.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobGiver_ExtractHoney.cs",
- "RelativeToolTip": "Jobs\\JobDriver_ExtractHoney\\JobGiver_ExtractHoney.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-03T15:51:21.323Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 11,
- "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",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
- "RelativeToolTip": "Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAuwBYAAAAIAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-03-03T15:50:37.468Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 14,
- "Title": "WorldComponent_AircraftManager.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
- "RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
- "RelativeToolTip": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-24T02:36:37.479Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 13,
- "Title": "GameComponent_DropPodInterceptor.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\GameComponent_DropPodInterceptor.cs",
- "RelativeDocumentMoniker": "Flyover\\GameComponent_DropPodInterceptor.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\GameComponent_DropPodInterceptor.cs",
- "RelativeToolTip": "Flyover\\GameComponent_DropPodInterceptor.cs",
- "ViewState": "AgIAAD0AAAAAAAAAAAA+wFcAAAAiAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-24T02:33:53.514Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 12,
- "Title": "CompAbilityEffect_ToggleDropPodIntercept.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_ToggleDropPodIntercept.cs",
- "RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_ToggleDropPodIntercept.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_ToggleDropPodIntercept.cs",
- "RelativeToolTip": "Abilities\\CompAbilityEffect_ToggleDropPodIntercept.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAFAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-24T02:33:22.192Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 15,
- "Title": "HediffComp_GestaltNode.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
- "RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
- "RelativeToolTip": "Hediffs\\ARA_GestaltNode\\HediffComp_GestaltNode.cs",
- "ViewState": "AgIAANwAAAAAAAAAAAAEwPIAAAARAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T13:37:57.93Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 16,
- "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": "AgIAAAAAAAAAAAAAAAAAAK4CAAAIAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T09:09:37.135Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 20,
- "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": "AgIAAM4BAAAAAAAAAAAMwOsBAABYAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T08:15:16.626Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 19,
- "Title": "ResearchBlueprintReaderManager.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintReaderManager.cs",
- "RelativeDocumentMoniker": "Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintReaderManager.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintReaderManager.cs",
- "RelativeToolTip": "Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintReaderManager.cs",
- "ViewState": "AgIAAKMCAAAAAAAAAAAnwL8CAAA4AAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T08:26:17.331Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 18,
- "Title": "CompProperties_AbilityFanShapedStunKnockback.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
- "RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
- "RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
- "ViewState": "AgIAABMAAAAAAAAAAAAAADIAAAAWAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T06:29:46.581Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 17,
- "Title": "CompAbilityEffect_FanShapedStunKnockback.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
- "RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
- "RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
- "ViewState": "AgIAAOMAAAAAAAAAAAAuwPcAAAARAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T06:29:34.172Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 21,
- "Title": "CompAbilityEffect_EjectOrgans.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
- "RelativeDocumentMoniker": "Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
- "RelativeToolTip": "Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAXAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T06:29:29.494Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 23,
- "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": "AgIAAFAAAAAAAAAAAAAQwBEAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T01:45:35.176Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 22,
- "Title": "CompProperties_HediffGiver.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",
- "RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",
- "RelativeToolTip": "Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",
- "ViewState": "AgIAAAgAAAAAAAAAAAAAAC8AAAAWAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-15T01:43:54.125Z"
}
]
}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs
deleted file mode 100644
index a997257..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs
+++ /dev/null
@@ -1,305 +0,0 @@
-using RimWorld;
-using System;
-using System.Linq;
-using System.Text;
-using UnityEngine;
-using Verse;
-using Verse.AI;
-
-namespace ArachnaeSwarm
-{
- public class CompAbilityEffect_PsychicLoadCost : CompAbilityEffect
- {
- public new CompProperties_AbilityPsychicLoadCost Props => (CompProperties_AbilityPsychicLoadCost)props;
-
- public float ActualLoadCost => Props.useFixedCost ? Props.fixedLoadCost : Props.loadCostRange.RandomInRange;
-
- public float GetPredictedLoadCost(bool useMaxCost = false)
- {
- if (Props.useFixedCost)
- {
- return Props.fixedLoadCost;
- }
-
- return useMaxCost ? Props.loadCostRange.max : Props.loadCostRange.Average;
- }
-
- public static float CalculateAbilityLoadCost(Ability ability, bool useMaxCost = false)
- {
- if (ability == null || ability.comps.NullOrEmpty())
- {
- return 0f;
- }
-
- float totalCost = 0f;
- foreach (CompAbilityEffect_PsychicLoadCost loadComp in ability.CompsOfType())
- {
- totalCost += loadComp.GetPredictedLoadCost(useMaxCost);
- }
-
- return totalCost;
- }
-
- public static float TotalQueuedLoadCost(Pawn pawn, bool useMaxCost = false)
- {
- if (pawn?.jobs == null)
- {
- return 0f;
- }
-
- float queuedCost = 0f;
-
- if (pawn.jobs.curJob?.verbToUse is Verb_CastAbility currentVerb)
- {
- queuedCost += CalculateAbilityLoadCost(currentVerb.ability, useMaxCost);
- }
-
- for (int i = 0; i < pawn.jobs.jobQueue.Count; i++)
- {
- QueuedJob queuedJob = pawn.jobs.jobQueue[i];
- if (queuedJob.job?.verbToUse is Verb_CastAbility queuedVerb)
- {
- queuedCost += CalculateAbilityLoadCost(queuedVerb.ability, useMaxCost);
- }
- }
-
- return queuedCost;
- }
-
- public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
- {
- base.Apply(target, dest);
-
- Pawn caster = parent.pawn;
- if (caster == null || caster.Dead || caster.Downed)
- {
- return;
- }
-
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- {
- Log.Warning($"[虫群术法] {caster.LabelCap} 没有有效的术法组件");
- return;
- }
-
- float loadCost = ActualLoadCost;
- bool wasOverloaded = spellHolder.IsOverloaded;
-
- spellHolder.AddPsychicLoad(loadCost, "ARA_UsePsychicLoadSkill".Translate(parent.def.label));
-
- bool isNowOverloaded = spellHolder.IsOverloaded;
- if (!wasOverloaded && isNowOverloaded)
- {
- Messages.Message("ARA_SwarmSpell_Load_OverloadWarning".Translate(caster.LabelShortCap), caster, MessageTypeDefOf.NegativeEvent);
- }
-
- if (wasOverloaded && Props.applyOverloadPenalty)
- {
- ApplyOverloadPenalty(caster, target);
- }
- }
-
- private void ApplyOverloadPenalty(Pawn caster, LocalTargetInfo target)
- {
- try
- {
- if (Props.overloadPenaltyHediff != null)
- {
- Hediff hediff = HediffMaker.MakeHediff(Props.overloadPenaltyHediff, caster);
- caster.health.AddHediff(hediff);
- }
-
- if (Props.destroyConsciousnessSource)
- {
- DestroyConsciousnessSourceParts(caster);
- }
-
- Messages.Message("ARA_SwarmSpell_Overload_Penalty".Translate(caster.LabelShortCap), caster, MessageTypeDefOf.NegativeHealthEvent);
- }
- catch (Exception ex)
- {
- Log.Error($"[虫群术法] 应用超载惩罚时出错: {ex.Message}");
- }
- }
-
- private void DestroyConsciousnessSourceParts(Pawn pawn)
- {
- try
- {
- var consciousnessParts = pawn.health.hediffSet.GetNotMissingParts()
- .Where(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- .ToList();
-
- if (consciousnessParts.Any())
- {
- foreach (BodyPartRecord part in consciousnessParts)
- {
- float partMaxHealth = part.def.GetMaxHealth(pawn);
- float damageAmount = partMaxHealth * Props.consciousnessSourceDamageMult;
-
- DamageInfo damage = new DamageInfo(
- DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: pawn,
- hitPart: part,
- category: DamageInfo.SourceCategory.ThingOrUnknown);
-
- pawn.TakeDamage(damage);
- }
-
- foreach (BodyPartRecord part in consciousnessParts)
- {
- if (!pawn.health.hediffSet.PartIsMissing(part))
- {
- DamageInfo finalDamage = new DamageInfo(
- DamageDefOf.Burn,
- 99999f,
- armorPenetration: 999f,
- instigator: pawn,
- hitPart: part);
- pawn.TakeDamage(finalDamage);
- }
- }
- }
- else
- {
- BodyPartRecord fallbackPart = pawn.RaceProps.body.AllParts
- .FirstOrDefault(p => p.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- ?? pawn.RaceProps.body.corePart;
-
- if (fallbackPart != null)
- {
- float damageAmount = fallbackPart.def.GetMaxHealth(pawn) * 2f;
- DamageInfo damage = new DamageInfo(
- DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: pawn,
- hitPart: fallbackPart);
- pawn.TakeDamage(damage);
- }
- }
- }
- catch (Exception ex)
- {
- Log.Error($"[虫群术法] 摧毁意识来源部位时出错: {ex.Message}");
- }
- }
-
- public override bool GizmoDisabled(out string reason)
- {
- Pawn caster = parent.pawn;
- if (caster == null || caster.Dead || caster.Downed)
- {
- reason = null;
- return false;
- }
-
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- {
- reason = null;
- return false;
- }
-
- if (spellHolder.LimitPsychicLoadAmount || !Props.ignoreOverloadCheck)
- {
- float thisCost = GetPredictedLoadCost(useMaxCost: true);
- float queuedCost = TotalQueuedLoadCost(caster, useMaxCost: true);
- float predictedLoad = spellHolder.PsychicLoad + thisCost + queuedCost;
-
- if (spellHolder.PsychicLoadCapacity > 0f && predictedLoad > spellHolder.PsychicLoadCapacity)
- {
- reason = "ARA_SwarmSpell_Load_OverloadWarning".Translate().Resolve();
- return true;
- }
- }
-
- reason = null;
- return false;
- }
-
- public override string ExtraTooltipPart()
- {
- if (!Props.showCostInGizmo)
- {
- return null;
- }
-
- Pawn caster = parent.pawn;
- if (caster == null)
- {
- return null;
- }
-
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null)
- {
- return null;
- }
-
- StringBuilder sb = new StringBuilder();
- string costLabel = Props.customLabel ?? "ARA_SwarmSpell_LoadCost".Translate();
- sb.AppendLine(costLabel.Colorize(ColoredText.TipSectionTitleColor));
-
- if (Props.useFixedCost)
- {
- sb.AppendLine("ARA_SwarmSpell_LoadCost_Fixed".Translate(Props.fixedLoadCost.ToString("F1")));
- }
- else
- {
- sb.AppendLine("ARA_SwarmSpell_LoadCost_Range".Translate(Props.loadCostRange.min.ToString("F1"), Props.loadCostRange.max.ToString("F1")));
- }
-
- if (spellHolder.IsOverloaded)
- {
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Load_OverloadWarning".Translate().Colorize(Color.red));
- sb.AppendLine("ARA_SwarmSpell_Overload_Penalty_Description".Translate());
- }
-
- return sb.ToString().TrimEndNewlines();
- }
-
- public override void DrawEffectPreview(LocalTargetInfo target)
- {
- base.DrawEffectPreview(target);
- }
-
- public override bool AICanTargetNow(LocalTargetInfo target)
- {
- Pawn caster = parent.pawn;
- if (caster == null)
- {
- return false;
- }
-
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null)
- {
- return false;
- }
-
- if (spellHolder.IsOverloaded)
- {
- return false;
- }
-
- float predictedLoad = spellHolder.PsychicLoad + GetPredictedLoadCost();
- if (spellHolder.LimitPsychicLoadAmount && spellHolder.PsychicLoadCapacity > 0f && predictedLoad > spellHolder.PsychicLoadCapacity)
- {
- return false;
- }
-
- float predictedPercent = spellHolder.PsychicLoadCapacity > 0f ? predictedLoad / spellHolder.PsychicLoadCapacity : 0f;
- if (predictedPercent > 0.9f)
- {
- return false;
- }
-
- return base.AICanTargetNow(target);
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs
deleted file mode 100644
index 5ecb773..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using RimWorld;
-using System;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 灵能负载消耗属性
- ///
- public class CompProperties_AbilityPsychicLoadCost : CompProperties_AbilityEffect
- {
- #region 字段
- public FloatRange loadCostRange = new FloatRange(1f, 5f); // 负载消耗范围
- public bool useFixedCost = false; // 是否使用固定值
- public float fixedLoadCost = 3f; // 固定负载消耗
- public bool showCostInGizmo = true; // 在Gizmo中显示消耗
- public string customLabel; // 自定义标签
- public bool ignoreOverloadCheck = true; // 忽略超载检查(总是可以施放)
- public EffecterDef successEffecter; // 成功施放效果
- public EffecterDef overloadEffecter; // 超载施放效果
-
- // 超载惩罚设置
- public bool applyOverloadPenalty = true; // 是否应用超载惩罚
- public float consciousnessSourceDamageMult = 1f; // 意识来源部位伤害倍数
- public HediffDef overloadPenaltyHediff; // 超载惩罚Hediff
- public bool destroyConsciousnessSource = true; // 是否摧毁意识来源部位
- #endregion
-
- #region 构造函数
- public CompProperties_AbilityPsychicLoadCost()
- {
- compClass = typeof(CompAbilityEffect_PsychicLoadCost);
- }
- #endregion
- }
-}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs
deleted file mode 100644
index 7db8adf..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs
+++ /dev/null
@@ -1,486 +0,0 @@
-using RimWorld;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 灵能负载转储技能效果
- /// 将施法者的灵能负载输出到目标身上,根据目标是否有灵能熵追踪器执行不同效果
- ///
- public class CompAbilityEffect_PsychicLoadDump : CompAbilityEffect
- {
- #region 属性
- public new CompProperties_AbilityPsychicLoadDump Props =>
- (CompProperties_AbilityPsychicLoadDump)props;
- #endregion
-
- #region 应用效果
- public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
- {
- base.Apply(target, dest);
-
- Pawn caster = parent.pawn;
- Pawn targetPawn = target.Pawn;
-
- if (caster == null || targetPawn == null || targetPawn.Dead || targetPawn.Downed)
- {
- Log.Warning("[虫群术法] 灵能负载转储: 施法者或目标无效");
- return;
- }
-
- // 获取施法者的术法持有组件
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- {
- Messages.Message("ARA_SwarmSpell_NoSpellHolder".Translate(caster.LabelShortCap),
- MessageTypeDefOf.RejectInput);
- return;
- }
-
- // 获取施法者当前的灵能负载
- float currentLoad = spellHolder.PsychicLoad;
- if (currentLoad <= 0f)
- {
- Messages.Message("ARA_SwarmSpell_NoLoadToDump".Translate(caster.LabelShortCap),
- MessageTypeDefOf.RejectInput);
- return;
- }
-
- // 记录施法者是否超载
- bool casterWasOverloaded = spellHolder.IsOverloaded;
-
- // 根据目标是否有灵能熵追踪器执行不同效果
- bool hasPsychicTracker = CheckTargetHasPsychicTracker(targetPawn);
-
- if (hasPsychicTracker)
- {
- // 有灵能熵追踪器:转化为PsychicEntropy
- ApplyPsychicEntropyEffect(caster, targetPawn, currentLoad, spellHolder);
- }
- else
- {
- // 没有灵能熵追踪器:摧毁意识来源器官
- ApplyConsciousnessDestruction(caster, targetPawn, currentLoad, spellHolder);
- }
-
- // 无论结果如何,清空施法者的灵能负载
- spellHolder.ReducePsychicLoad(currentLoad, "转储灵能负载");
-
- // 显示效果和消息
- ShowEffectsAndMessages(caster, targetPawn, currentLoad, hasPsychicTracker, casterWasOverloaded);
- }
- #endregion
-
- #region 检查目标是否有灵能熵追踪器
- ///
- /// 检查目标是否有灵能熵追踪器
- ///
- private bool CheckTargetHasPsychicTracker(Pawn target)
- {
- try
- {
- // 方法1:直接检查psychicEntropy字段
- var entropyField = typeof(Pawn).GetField("psychicEntropy");
- if (entropyField != null)
- {
- object entropyObj = entropyField.GetValue(target);
- if (entropyObj != null)
- {
- // 检查是否是Pawn_PsychicEntropyTracker类型
- var entropyType = entropyObj.GetType();
- if (entropyType.Name == "Pawn_PsychicEntropyTracker")
- {
- // 进一步检查是否有TryAddEntropy方法
- var addEntropyMethod = entropyType.GetMethod("TryAddEntropy");
- if (addEntropyMethod != null)
- {
- return true;
- }
- }
- }
- }
-
- // 方法2:检查是否有PsychicSensitivity属性
- if (target.RaceProps.Humanlike)
- {
- // 人类类种族通常有灵能熵追踪器
- float psychicSensitivity = target.GetStatValue(StatDefOf.PsychicSensitivity);
- if (psychicSensitivity > 0.01f)
- {
- return true;
- }
- }
-
- // 方法3:检查是否有Psylink相关Hediff
- Hediff psylink = target.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PsychicAmplifier);
- if (psylink != null)
- {
- return true;
- }
-
- // 方法4:检查是否有PsychicEntropy Hediff
- Hediff entropyHediff = target.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PsychicEntropy);
- if (entropyHediff != null)
- {
- return true;
- }
-
- return false;
- }
- catch (System.Exception ex)
- {
- Log.Warning($"[虫群术法] 检查目标灵能熵追踪器时出错: {ex.Message}");
- return false;
- }
- }
-
- ///
- /// 获取目标的灵能熵追踪器(如果存在)
- ///
- private object GetPsychicEntropyTracker(Pawn target)
- {
- try
- {
- var entropyField = typeof(Pawn).GetField("psychicEntropy");
- if (entropyField != null)
- {
- return entropyField.GetValue(target);
- }
- return null;
- }
- catch (System.Exception)
- {
- return null;
- }
- }
- #endregion
-
- #region 应用灵能熵效果
- ///
- /// 将灵能负载转化为PsychicEntropy应用到目标
- ///
- private void ApplyPsychicEntropyEffect(Pawn caster, Pawn target, float loadAmount, Comp_SwarmSpellHolder spellHolder)
- {
- try
- {
- // 计算转化的熵值(1:10转化比)
- float entropyAmount = loadAmount * Props.conversionRatio;
-
- // 获取目标的灵能熵追踪器
- object entropyTracker = GetPsychicEntropyTracker(target);
- if (entropyTracker != null)
- {
- // 使用反射调用TryAddEntropy方法
- System.Type entropyType = entropyTracker.GetType();
- var addEntropyMethod = entropyType.GetMethod("TryAddEntropy",
- new System.Type[] { typeof(float), typeof(Thing), typeof(bool), typeof(bool) });
-
- if (addEntropyMethod != null)
- {
- bool success = (bool)addEntropyMethod.Invoke(entropyTracker,
- new object[] { entropyAmount, caster, Props.scaleBySensitivity, Props.allowOverLimit });
-
- if (success)
- {
- // 成功添加熵值
- ShowEntropyTransferEffect(caster, target, entropyAmount);
- }
- else
- {
- // 添加熵值失败(可能达到上限)
- Messages.Message("ARA_SwarmSpell_EntropyTransferFailed".Translate(target.LabelShortCap),
- target, MessageTypeDefOf.NegativeEvent);
- }
- }
- else
- {
- // 如果没有TryAddEntropy方法,尝试其他方法
- ApplyFallbackEffect(target, loadAmount);
- }
- }
- else
- {
- // 没有找到追踪器,使用后备效果
- ApplyFallbackEffect(target, loadAmount);
- }
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 应用灵能熵效果时出错: {ex.Message}\n{ex.StackTrace}");
- ApplyFallbackEffect(target, loadAmount);
- }
- }
-
- ///
- /// 后备效果(当无法添加熵值时使用)
- ///
- private void ApplyFallbackEffect(Pawn target, float loadAmount)
- {
- // 应用一些伤害作为后备
- float damageAmount = loadAmount * Props.fallbackDamageMultiplier;
- DamageInfo damage = new DamageInfo(
- Props.fallbackDamageType ?? DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: parent.pawn
- );
- target.TakeDamage(damage);
- }
-
- ///
- /// 显示熵值转移效果
- ///
- private void ShowEntropyTransferEffect(Pawn caster, Pawn target, float entropyAmount)
- {
- // 显示效果
- if (Props.entropyTransferEffecter != null)
- {
- Effecter effecter = Props.entropyTransferEffecter.Spawn();
- effecter.Trigger(new TargetInfo(caster.Position, caster.Map), new TargetInfo(target.Position, target.Map));
- effecter.Cleanup();
- }
-
- // 显示熵值转移消息
- if (Props.showEntropyTransferMessage)
- {
- Messages.Message("ARA_SwarmSpell_EntropyTransferred".Translate(
- caster.LabelShortCap, target.LabelShortCap, entropyAmount.ToString("F1")),
- target, MessageTypeDefOf.NegativeEvent);
- }
- }
- #endregion
-
- #region 应用意识摧毁效果
- ///
- /// 摧毁目标的意识来源器官
- ///
- private void ApplyConsciousnessDestruction(Pawn caster, Pawn target, float loadAmount, Comp_SwarmSpellHolder spellHolder)
- {
- try
- {
- // 获取所有意识来源部位
- var consciousnessParts = target.health.hediffSet.GetNotMissingParts()
- .Where(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- .ToList();
-
- if (consciousnessParts.Count == 0)
- {
- // 如果没有意识来源器官,应用普通伤害
- ApplyNoConsciousnessFallback(target, loadAmount);
- return;
- }
-
- int destroyedCount = 0;
- float loadPerPart = loadAmount / consciousnessParts.Count;
-
- foreach (var part in consciousnessParts)
- {
- if (TryDestroyConsciousnessPart(target, part, loadPerPart))
- {
- destroyedCount++;
-
- // 显示伤害效果
- if (Props.consciousnessDestroyFleck != null && target.Map != null)
- {
- FleckMaker.Static(target.Position, target.Map, Props.consciousnessDestroyFleck);
- }
- }
- }
-
- // 如果摧毁了任何意识来源器官,应用惩罚效果
- if (destroyedCount > 0)
- {
- ApplyConsciousnessPenalty(target);
-
- // 显示摧毁消息
- if (Props.showConsciousnessDestroyMessage)
- {
- Messages.Message("ARA_SwarmSpell_ConsciousnessDestroyed".Translate(
- target.LabelShortCap, destroyedCount),
- target, MessageTypeDefOf.NegativeHealthEvent);
- }
- }
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 摧毁意识来源器官时出错: {ex.Message}\n{ex.StackTrace}");
- }
- }
-
- ///
- /// 尝试摧毁意识来源器官
- ///
- private bool TryDestroyConsciousnessPart(Pawn pawn, BodyPartRecord part, float loadPerPart)
- {
- try
- {
- // 计算伤害(基于负载和配置的伤害倍数)
- float damageAmount = part.def.GetMaxHealth(pawn) * Props.partDestructionDamageMult +
- (loadPerPart * Props.loadDamageMultiplier);
-
- DamageInfo damage = new DamageInfo(
- Props.destroyDamageType ?? DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: parent.pawn,
- hitPart: part,
- category: DamageInfo.SourceCategory.ThingOrUnknown
- );
-
- pawn.TakeDamage(damage);
-
- // 确保部位被摧毁
- if (!pawn.health.hediffSet.PartIsMissing(part))
- {
- DamageInfo finalDamage = new DamageInfo(
- Props.destroyDamageType ?? DamageDefOf.Burn,
- 99999f,
- armorPenetration: 999f,
- instigator: parent.pawn,
- hitPart: part
- );
- pawn.TakeDamage(finalDamage);
- }
-
- return true;
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 摧毁部位 {part.Label} 时出错: {ex.Message}");
- return false;
- }
- }
-
- ///
- /// 没有意识来源器官时的后备效果
- ///
- private void ApplyNoConsciousnessFallback(Pawn target, float loadAmount)
- {
- // 对核心部位造成伤害
- BodyPartRecord corePart = target.RaceProps.body.corePart;
- if (corePart != null)
- {
- float damageAmount = loadAmount * Props.noConsciousnessDamageMultiplier;
- DamageInfo damage = new DamageInfo(
- Props.destroyDamageType ?? DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: parent.pawn,
- hitPart: corePart
- );
- target.TakeDamage(damage);
-
- if (Props.showNoConsciousnessMessage)
- {
- Messages.Message("ARA_SwarmSpell_NoConsciousnessFallback".Translate(
- target.LabelShortCap, damageAmount.ToString("F0")),
- target, MessageTypeDefOf.NegativeEvent);
- }
- }
- }
-
- ///
- /// 应用意识来源器官被摧毁的惩罚
- ///
- private void ApplyConsciousnessPenalty(Pawn pawn)
- {
- // 添加意识惩罚Hediff
- if (Props.consciousnessPenaltyHediff != null)
- {
- try
- {
- Hediff penalty = HediffMaker.MakeHediff(Props.consciousnessPenaltyHediff, pawn);
- pawn.health.AddHediff(penalty);
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 添加意识惩罚Hediff时出错: {ex.Message}");
- }
- }
-
- // 显示效果
- if (Props.penaltyEffecter != null)
- {
- Effecter effecter = Props.penaltyEffecter.Spawn();
- effecter.Trigger(new TargetInfo(pawn.Position, pawn.Map), new TargetInfo(pawn.Position, pawn.Map));
- effecter.Cleanup();
- }
- }
- #endregion
-
- #region 视觉效果和消息
- ///
- /// 显示效果和消息
- ///
- private void ShowEffectsAndMessages(Pawn caster, Pawn target, float loadAmount, bool hasPsychicTracker, bool casterWasOverloaded)
- {
- // 显示主效果
- if (Props.mainEffecter != null)
- {
- Effecter effecter = Props.mainEffecter.Spawn();
- effecter.Trigger(new TargetInfo(caster.Position, caster.Map), new TargetInfo(target.Position, target.Map));
- effecter.Cleanup();
- }
-
- // 显示负载转储消息
- if (Props.showDumpMessage)
- {
- string messageKey = hasPsychicTracker ?
- "ARA_SwarmSpell_LoadDumped_Entropy" :
- "ARA_SwarmSpell_LoadDumped_Destruction";
-
- string message = messageKey.Translate(
- caster.LabelShortCap,
- target.LabelShortCap,
- loadAmount.ToString("F1"));
-
- Messages.Message(message, caster, MessageTypeDefOf.PositiveEvent);
- }
-
- // 显示施法者状态消息
- if (casterWasOverloaded && Props.showOverloadReliefMessage)
- {
- Messages.Message("ARA_SwarmSpell_OverloadRelieved".Translate(caster.LabelShortCap),
- caster, MessageTypeDefOf.PositiveEvent);
- }
- }
- #endregion
-
- #region AI 行为
- public override bool AICanTargetNow(LocalTargetInfo target)
- {
- Pawn caster = parent.pawn;
- if (caster == null)
- return false;
-
- Pawn targetPawn = target.Pawn;
- if (targetPawn == null || targetPawn.Dead || (targetPawn.Downed && !Props.canTargetDowned))
- return false;
-
- // 检查施法者是否有术法组件
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- return false;
-
- // AI不会在没有负载时使用此技能
- if (spellHolder.PsychicLoad <= 0f)
- return false;
-
- // AI倾向于在超载时使用此技能
- float overloadUrgency = spellHolder.IsOverloaded ? 0.8f : (spellHolder.PsychicLoadPercent * 0.5f);
-
- // AI考虑目标的威胁程度
- float threatScore = targetPawn.Downed ? 0f : (targetPawn.kindDef.combatPower / 100f);
-
- // 综合评分:超载越严重、目标威胁越大,越可能使用
- float totalScore = overloadUrgency + (threatScore * 0.5f);
-
- return totalScore > 0.5f && base.AICanTargetNow(target);
- }
- #endregion
- }
-}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompProperties_AbilityPsychicLoadDump.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompProperties_AbilityPsychicLoadDump.cs
deleted file mode 100644
index 3e0e613..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompProperties_AbilityPsychicLoadDump.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 灵能负载转储技能属性
- ///
- public class CompProperties_AbilityPsychicLoadDump : CompProperties_AbilityEffect
- {
- #region 转化设置
- ///
- /// 转化比例(1负载 = X熵值)
- ///
- public float conversionRatio = 10f;
-
- ///
- /// 是否根据目标的灵能敏感度缩放
- ///
- public bool scaleBySensitivity = true;
-
- ///
- /// 是否允许超过目标熵值上限
- ///
- public bool allowOverLimit = false;
- #endregion
-
- #region 目标选择
- ///
- /// 是否可以对倒下的目标使用
- ///
- public bool canTargetDowned = false;
- #endregion
-
- #region 器官摧毁设置
- ///
- /// 部位摧毁基础伤害倍数(基于部位最大生命值)
- ///
- public float partDestructionDamageMult = 1.5f;
-
- ///
- /// 负载伤害倍数(负载 * 此倍数)
- ///
- public float loadDamageMultiplier = 5f;
-
- ///
- /// 没有意识来源器官时的伤害倍数
- ///
- public float noConsciousnessDamageMultiplier = 3f;
-
- ///
- /// 后备效果伤害倍数(当无法添加熵值时)
- ///
- public float fallbackDamageMultiplier = 2f;
-
- ///
- /// 摧毁部位使用的伤害类型
- ///
- public DamageDef destroyDamageType = null;
-
- ///
- /// 后备效果伤害类型
- ///
- public DamageDef fallbackDamageType = null;
- #endregion
-
- #region 效果设置
- ///
- /// 主效果器
- ///
- public EffecterDef mainEffecter = null;
-
- ///
- /// 熵值转移效果器
- ///
- public EffecterDef entropyTransferEffecter = null;
-
- ///
- /// 意识摧毁特效
- ///
- public FleckDef consciousnessDestroyFleck = null;
-
- ///
- /// 惩罚效果器
- ///
- public EffecterDef penaltyEffecter = null;
-
- ///
- /// 意识惩罚Hediff
- ///
- public HediffDef consciousnessPenaltyHediff = null;
- #endregion
-
- #region 消息设置
- ///
- /// 是否显示转储消息
- ///
- public bool showDumpMessage = true;
-
- ///
- /// 是否显示熵值转移消息
- ///
- public bool showEntropyTransferMessage = true;
-
- ///
- /// 是否显示意识摧毁消息
- ///
- public bool showConsciousnessDestroyMessage = true;
-
- ///
- /// 是否显示没有意识来源器官消息
- ///
- public bool showNoConsciousnessMessage = true;
-
- ///
- /// 是否显示超载解除消息
- ///
- public bool showOverloadReliefMessage = true;
- #endregion
-
- public CompProperties_AbilityPsychicLoadDump()
- {
- compClass = typeof(CompAbilityEffect_PsychicLoadDump);
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompAbilityEffect_PsychicResearchHarvest.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompAbilityEffect_PsychicResearchHarvest.cs
deleted file mode 100644
index 952e81f..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompAbilityEffect_PsychicResearchHarvest.cs
+++ /dev/null
@@ -1,412 +0,0 @@
-using RimWorld;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 灵能科研点收割技能效果
- /// 从目标身上收割灵能科研点,并摧毁目标的意识来源器官
- ///
- public class CompAbilityEffect_PsychicResearchHarvest : CompAbilityEffect
- {
- #region 属性
- public new CompProperties_AbilityPsychicResearchHarvest Props =>
- (CompProperties_AbilityPsychicResearchHarvest)props;
- #endregion
-
- #region 应用效果
- public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
- {
- base.Apply(target, dest);
-
- Pawn caster = parent.pawn;
- Pawn targetPawn = target.Pawn;
-
- if (caster == null || targetPawn == null || targetPawn.Dead || targetPawn.Downed)
- {
- Log.Warning("[虫群术法] 灵能科研点收割: 施法者或目标无效");
- return;
- }
-
- // 获取施法者的术法持有组件
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- {
- Messages.Message("ARA_SwarmSpell_NoSpellHolder".Translate(caster.LabelShortCap),
- MessageTypeDefOf.RejectInput);
- return;
- }
-
- // 计算应获得的科研点
- float researchPoints = CalculateResearchPoints(targetPawn);
-
- // 添加到施法者的科研点
- bool success = spellHolder.AddPsychicResearchPoints(researchPoints, "收割目标灵能");
-
- // 摧毁目标的意识来源器官
- DestroyConsciousnessSourceParts(targetPawn);
-
- // 显示效果和消息
- ShowEffectsAndMessages(caster, targetPawn, researchPoints, success);
- }
- #endregion
-
- #region 计算科研点
- ///
- /// 计算从目标身上可收割的灵能科研点
- ///
- private float CalculateResearchPoints(Pawn targetPawn)
- {
- float baseAmount = Props.baseAmount;
- float intelligenceMultiplier = Props.intelligenceMultiplier;
- float consciousnessMultiplier = Props.consciousnessMultiplier;
-
- // 获取目标的智识(Intellectual)技能等级
- // 如果没有智识技能(比如动物),视为1
- float intelligenceValue = 1f;
- if (targetPawn.skills != null)
- {
- SkillRecord intellectualSkill = targetPawn.skills.GetSkill(SkillDefOf.Intellectual);
- if (intellectualSkill != null)
- {
- // 使用技能等级(0-20)作为智识值
- intelligenceValue = intellectualSkill.Level;
- if (intelligenceValue <= 0) intelligenceValue = 1f;
- }
- }
-
- // 获取目标的意识(Consciousness)能力值
- float consciousnessValue = targetPawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness);
- if (consciousnessValue < 0) consciousnessValue = 0;
-
- // 计算公式:基础数 + (智识 * 智识倍率) + (意识 * 意识倍率)
- float researchPoints = baseAmount +
- (intelligenceValue * intelligenceMultiplier) +
- (consciousnessValue * consciousnessMultiplier);
-
- // 应用乘数
- researchPoints *= Props.overallMultiplier;
-
- // 应用随机范围(如果有)
- if (Props.useRandomRange)
- {
- researchPoints = researchPoints * Props.randomRange.RandomInRange;
- }
-
- // 确保最小值
- researchPoints = Mathf.Max(researchPoints, Props.minimumAmount);
-
- return researchPoints;
- }
-
- #endregion
-
- #region 摧毁意识来源器官
- ///
- /// 摧毁目标的所有意识来源器官
- ///
- private void DestroyConsciousnessSourceParts(Pawn targetPawn)
- {
- if (targetPawn == null || targetPawn.Dead || targetPawn.Downed)
- return;
-
- try
- {
- // 获取所有意识来源部位
- var consciousnessParts = targetPawn.health.hediffSet.GetNotMissingParts()
- .Where(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- .ToList();
-
- if (consciousnessParts.Count == 0)
- {
- return;
- }
-
- int destroyedCount = 0;
-
- foreach (var part in consciousnessParts)
- {
- // 尝试用最高优先级的方式摧毁部位
- if (TryDestroyBodyPart(targetPawn, part))
- {
- destroyedCount++;
-
- // 显示伤害效果
- if (Props.destroyFleck != null && targetPawn.Map != null)
- {
- FleckMaker.Static(targetPawn.Position, targetPawn.Map, Props.destroyFleck);
- }
- }
- }
-
- // 如果摧毁了任何意识来源器官,应用惩罚效果
- if (destroyedCount > 0)
- {
- ApplyConsciousnessPenalty(targetPawn);
- }
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 摧毁意识来源器官时出错: {ex.Message}\n{ex.StackTrace}");
- }
- }
-
- ///
- /// 尝试摧毁身体部位
- ///
- private bool TryDestroyBodyPart(Pawn pawn, BodyPartRecord part)
- {
- try
- {
- // 方法1:直接伤害(最可靠)
- float damageAmount = part.def.GetMaxHealth(pawn) * Props.partDestructionDamageMult;
-
- DamageInfo damage = new DamageInfo(
- Props.destroyDamageType ?? DamageDefOf.Burn,
- damageAmount,
- armorPenetration: 999f,
- instigator: parent.pawn,
- hitPart: part,
- category: DamageInfo.SourceCategory.ThingOrUnknown
- );
-
- pawn.TakeDamage(damage);
-
- // 方法2:如果部位仍然存在,尝试强制移除
- if (!pawn.health.hediffSet.PartIsMissing(part))
- {
- // 施加更大的伤害确保摧毁
- DamageInfo finalDamage = new DamageInfo(
- Props.destroyDamageType ?? DamageDefOf.Burn,
- 99999f,
- armorPenetration: 999f,
- instigator: parent.pawn,
- hitPart: part
- );
- pawn.TakeDamage(finalDamage);
-
- // 如果还是不行,尝试添加部件缺失Hediff
- if (!pawn.health.hediffSet.PartIsMissing(part))
- {
- pawn.health.AddHediff(HediffDefOf.MissingBodyPart, part);
- }
- }
-
- return true;
- }
- catch (System.Exception ex)
- {
- Log.Error($"[虫群术法] 摧毁部位 {part.Label} 时出错: {ex.Message}");
- return false;
- }
- }
-
- ///
- /// 应用意识来源器官被摧毁的惩罚
- ///
- private void ApplyConsciousnessPenalty(Pawn pawn)
- {
- // 显示效果
- if (Props.penaltyEffecter != null)
- {
- Effecter effecter = Props.penaltyEffecter.Spawn();
- effecter.Trigger(new TargetInfo(pawn.Position, pawn.Map), new TargetInfo(pawn.Position, pawn.Map));
- effecter.Cleanup();
- }
- }
- #endregion
-
- #region 视觉效果和消息
- ///
- /// 显示效果和消息
- ///
- private void ShowEffectsAndMessages(Pawn caster, Pawn target, float researchPoints, bool success)
- {
- // 显示收割效果
- if (Props.harvestEffecter != null)
- {
- Effecter effecter = Props.harvestEffecter.Spawn();
- effecter.Trigger(new TargetInfo(caster.Position, caster.Map), new TargetInfo(target.Position, target.Map));
- effecter.Cleanup();
- }
-
- // 显示收获消息
- if (Props.showHarvestMessage)
- {
- string message;
- if (Props.customHarvestMessageKey.NullOrEmpty())
- {
- message = "ARA_SwarmSpell_ResearchHarvest".Translate(
- caster.LabelShortCap,
- target.LabelShortCap,
- researchPoints.ToString("F1"));
- }
- else
- {
- message = Props.customHarvestMessageKey.Translate(
- caster.LabelShortCap,
- target.LabelShortCap,
- researchPoints.ToString("F1"));
- }
-
- Messages.Message(message, caster, MessageTypeDefOf.PositiveEvent);
- }
- }
- #endregion
-
- #region 验证和工具提示
- public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
- {
- if (!base.Valid(target, throwMessages))
- return false;
-
- Pawn targetPawn = target.Pawn;
- if (targetPawn == null)
- {
- if (throwMessages)
- Messages.Message("需要选择一个目标单位", MessageTypeDefOf.RejectInput);
- return false;
- }
-
- // 检查目标是否活着且没有倒下(如果技能不允许对倒下单位使用)
- if (!Props.canTargetDowned && targetPawn.Downed)
- {
- if (throwMessages)
- Messages.Message("目标已经倒下,无法收割", MessageTypeDefOf.RejectInput);
- return false;
- }
-
- // 检查目标是否有意识来源器官(可选检查)
- if (Props.requireConsciousnessSource)
- {
- var consciousnessParts = targetPawn.health.hediffSet.GetNotMissingParts()
- .Where(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- .ToList();
-
- if (consciousnessParts.Count == 0)
- {
- if (throwMessages)
- Messages.Message("目标没有可收割的意识来源器官", MessageTypeDefOf.RejectInput);
- return false;
- }
- }
-
- // 检查施法者是否有术法组件且科研点未满
- Pawn caster = parent.pawn;
- if (caster != null)
- {
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null)
- {
- if (throwMessages)
- Messages.Message("施法者没有灵能术法系统", MessageTypeDefOf.RejectInput);
- return false;
- }
-
- if (!spellHolder.IsSystemInitialized)
- {
- if (throwMessages)
- Messages.Message("灵能术法系统未初始化", MessageTypeDefOf.RejectInput);
- return false;
- }
-
- // 检查科研点是否已满
- if (!Props.allowOverflow && spellHolder.PsychicResearchPoints >= spellHolder.MaxPsychicResearchPoints)
- {
- if (throwMessages)
- Messages.Message("灵能科研点已达上限,无法收割", MessageTypeDefOf.RejectInput);
- return false;
- }
- }
-
- return true;
- }
- #endregion
-
- #region AI 行为
- public override bool AICanTargetNow(LocalTargetInfo target)
- {
- Pawn caster = parent.pawn;
- if (caster == null)
- return false;
-
- Pawn targetPawn = target.Pawn;
- if (targetPawn == null || targetPawn.Dead || (targetPawn.Downed && !Props.canTargetDowned))
- return false;
-
- // 检查施法者是否有术法组件
- Comp_SwarmSpellHolder spellHolder = caster.TryGetComp();
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- return false;
-
- // AI不会在科研点已满时使用此技能
- if (!Props.allowOverflow && spellHolder.PsychicResearchPoints >= spellHolder.MaxPsychicResearchPoints)
- return false;
-
- // AI倾向于选择智识和意识高的目标
- float predictedPoints = CalculateResearchPoints(targetPawn);
-
- // 计算收益评估
- float benefitScore = predictedPoints / spellHolder.MaxPsychicResearchPoints;
-
- // AI考虑目标的威胁程度
- float threatScore = targetPawn.Downed ? 0f : (targetPawn.kindDef.combatPower / 100f);
-
- // 综合评分:收益高、威胁低的目标优先
- float totalScore = benefitScore - (threatScore * 0.3f);
-
- return totalScore > 0.2f && base.AICanTargetNow(target);
- }
- #endregion
-
- #region 调试和工具方法
- ///
- /// 获取目标意识来源器官的数量
- ///
- public int GetTargetConsciousnessPartCount(Pawn target)
- {
- if (target == null || target.Dead || target.Downed)
- return 0;
-
- return target.health.hediffSet.GetNotMissingParts()
- .Count(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true);
- }
-
- ///
- /// 获取技能影响的详细描述
- ///
- public string GetDetailedEffectDescription(Pawn target)
- {
- StringBuilder sb = new StringBuilder();
-
- int partCount = GetTargetConsciousnessPartCount(target);
- float predictedPoints = CalculateResearchPoints(target);
-
- sb.AppendLine("灵能科研点收割效果预测:");
- sb.AppendLine($"目标: {target.LabelCap}");
- sb.AppendLine($"意识来源器官: {partCount} 个");
- sb.AppendLine($"预计收割科研点: {predictedPoints:F1}");
-
- if (partCount > 0)
- {
- sb.AppendLine();
- sb.AppendLine("将被摧毁的部位:");
- var parts = target.health.hediffSet.GetNotMissingParts()
- .Where(part => part.def.tags?.Contains(BodyPartTagDefOf.ConsciousnessSource) == true)
- .ToList();
-
- foreach (var part in parts)
- {
- sb.AppendLine($" • {part.LabelCap} (健康: {target.health.hediffSet.GetPartHealth(part):F0}/{part.def.GetMaxHealth(target):F0})");
- }
- }
-
- return sb.ToString();
- }
- #endregion
- }
-}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompProperties_AbilityPsychicResearchHarvest.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompProperties_AbilityPsychicResearchHarvest.cs
deleted file mode 100644
index aec4d39..0000000
--- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicResearchHarvest/CompProperties_AbilityPsychicResearchHarvest.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 灵能科研点收割技能属性
- ///
- public class CompProperties_AbilityPsychicResearchHarvest : CompProperties_AbilityEffect
- {
- #region 科研点计算字段
- ///
- /// 基础收割量
- ///
- public float baseAmount = 100f;
-
- ///
- /// 智识倍率
- ///
- public float intelligenceMultiplier = 50f;
-
- ///
- /// 意识倍率
- ///
- public float consciousnessMultiplier = 100f;
-
- ///
- /// 全局乘数
- ///
- public float overallMultiplier = 1f;
-
- ///
- /// 是否使用随机范围
- ///
- public bool useRandomRange = false;
-
- ///
- /// 随机范围(乘数)
- ///
- public FloatRange randomRange = new FloatRange(0.8f, 1.2f);
-
- ///
- /// 最低收割量(确保至少收获这么多)
- ///
- public float minimumAmount = 10f;
-
- ///
- /// 是否允许科研点溢出(超过上限)
- ///
- public bool allowOverflow = false;
- #endregion
-
- #region 目标选择和验证字段
- ///
- /// 是否可以对倒下的目标使用
- ///
- public bool canTargetDowned = false;
-
- ///
- /// 是否要求目标必须有意识来源器官
- ///
- public bool requireConsciousnessSource = true;
-
- ///
- /// 在工具提示中显示详细计算
- ///
- public bool showDetailedCalculation = true;
- #endregion
-
- #region 器官摧毁字段
- ///
- /// 部位摧毁伤害倍数(基于部位最大生命值)
- ///
- public float partDestructionDamageMult = 2.0f;
-
- ///
- /// 摧毁部位使用的伤害类型
- ///
- public DamageDef destroyDamageType = null;
-
- ///
- /// 摧毁部位时的特效
- ///
- public FleckDef destroyFleck = null;
-
- ///
- /// 是否显示器官摧毁消息
- ///
- public bool showDestroyMessage = true;
-
- ///
- /// 是否可能杀死目标
- ///
- public bool canKillTarget = false;
-
- ///
- /// 完全摧毁意识来源器官时的杀死几率
- ///
- public float killChanceOnCompleteDestruction = 0.3f;
-
- ///
- /// 杀死目标时使用的伤害类型
- ///
- public DamageDef killDamageType = null;
-
- ///
- /// 是否显示杀死消息
- ///
- public bool showKillMessage = true;
- #endregion
-
- #region 效果和消息字段
- ///
- /// 收割时的特效
- ///
- public EffecterDef harvestEffecter = null;
-
- ///
- /// 惩罚效果
- ///
- public EffecterDef penaltyEffecter = null;
-
- ///
- /// 意识惩罚Hediff
- ///
- public HediffDef consciousnessPenaltyHediff = null;
-
- ///
- /// 失去意识Hediff
- ///
- public HediffDef unconsciousnessHediff = null;
-
- ///
- /// 是否显示收割消息
- ///
- public bool showHarvestMessage = true;
-
- ///
- /// 自定义收割消息翻译键
- ///
- public string customHarvestMessageKey = null;
-
- ///
- /// 是否显示目标受损消息
- ///
- public bool showTargetDamageMessage = true;
- #endregion
-
- #region 构造函数
- public CompProperties_AbilityPsychicResearchHarvest()
- {
- compClass = typeof(CompAbilityEffect_PsychicResearchHarvest);
- }
- #endregion
- }
-}
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 96afed6..93958dd 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -40,12 +40,6 @@
-
-
-
-
-
-
@@ -376,14 +370,8 @@
-
-
-
-
-
-
diff --git a/Source/ArachnaeSwarm/Hediffs/HediffComp_SpawnPawnOnRemoved.cs b/Source/ArachnaeSwarm/Hediffs/HediffComp_SpawnPawnOnRemoved.cs
index 17de95a..8dfb6d5 100644
--- a/Source/ArachnaeSwarm/Hediffs/HediffComp_SpawnPawnOnRemoved.cs
+++ b/Source/ArachnaeSwarm/Hediffs/HediffComp_SpawnPawnOnRemoved.cs
@@ -50,8 +50,6 @@ namespace ArachnaeSwarm
///
public override void CompPostPostRemoved()
{
- base.CompPostPostRemoved();
-
if (this.Pawn == null || this.Pawn.Map == null || Props.pawnKindDefs.NullOrEmpty())
{
ArachnaeLog.Debug("ArachnaeSwarm: HediffComp_SpawnPawnOnRemoved tried to spawn a pawn but required data was missing (Pawn, Map, or pawnKindDefs).");
@@ -90,6 +88,8 @@ namespace ArachnaeSwarm
ArachnaeLog.Debug($"ArachnaeSwarm: Failed to generate pawn of kind {selectedPawnKindDef.defName}.");
}
}
+
+ base.CompPostPostRemoved();
}
///
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/CompProperties_PawnResearchBlueprintReader.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/CompProperties_PawnResearchBlueprintReader.cs
deleted file mode 100644
index 62107ca..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/CompProperties_PawnResearchBlueprintReader.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using RimWorld;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- public class CompProperties_PawnResearchBlueprintReader : CompProperties
- {
- ///
- /// 是否允许该Pawn进行科技研究
- ///
- public bool canResearch = true;
-
- ///
- /// 研究速度乘数(基于智力等级)
- ///
- public float researchSpeedMultiplier = 1.0f;
-
- ///
- /// 是否显示研究进度Gizmo
- ///
- public bool showResearchGizmo = true;
-
- ///
- /// 是否自动开始研究(当有未完成科技时)
- ///
- public bool autoStartResearch = true;
-
- ///
- /// 所需研究标签页(默认为阿拉克涅科技标签页)
- ///
- public ResearchTabDef requiredResearchTab = null; // 将在PostLoad中设置默认值
-
- ///
- /// 每秒研究的点数(基础值,会乘以智力等级)
- ///
- public float baseResearchPointsPerSecond = 1.0f;
-
- ///
- /// 是否使用灵能科研点(如果为true,需要Comp_SwarmSpellHolder)
- ///
- public bool usePsychicResearchPoints = true;
-
- ///
- /// 研究完成的提示消息翻译键
- ///
- public string researchCompletedMessageKey = "ARA_PawnResearch_Completed";
-
- ///
- /// 研究开始的提示消息翻译键
- ///
- public string researchStartedMessageKey = "ARA_PawnResearch_Started";
-
- ///
- /// 灵能科研点不足的提示消息翻译键
- ///
- public string researchNoPointsMessageKey = "ARA_PawnResearch_NoPoints";
-
- public CompProperties_PawnResearchBlueprintReader()
- {
- this.compClass = typeof(Comp_PawnResearchBlueprintReader);
- }
-
- public void PostLoad()
- {
- // 如果没有指定研究标签页,使用默认的阿拉克涅科技标签页
- if (requiredResearchTab == null)
- {
- requiredResearchTab = DefDatabase.GetNamedSilentFail("ARA_ResearchTab");
- }
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Comp_PawnResearchBlueprintReader.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Comp_PawnResearchBlueprintReader.cs
deleted file mode 100644
index af89249..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Comp_PawnResearchBlueprintReader.cs
+++ /dev/null
@@ -1,855 +0,0 @@
-using RimWorld;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- public class Comp_PawnResearchBlueprintReader : ThingComp
- {
- // === 字段定义 ===
-
- ///
- /// 当前研究的科技项目
- ///
- private ResearchProjectDef currentResearch = null;
-
- ///
- /// 是否正在研究中
- ///
- private bool isResearching = false;
-
- ///
- /// 灵能术法组件引用
- ///
- public Comp_SwarmSpellHolder spellHolder = null;
-
- ///
- /// 上次研究更新的tick数
- ///
- private int lastResearchTick = -1;
-
- ///
- /// 研究进度(已添加到ResearchManager中的进度)
- ///
- private float currentProgress = 0f;
-
- ///
- /// 研究开始时间(游戏内ticks)
- ///
- private int researchStartTick = -1;
-
- ///
- /// 临时存储的研究点数(用于累积小数)
- ///
- private float accumulatedResearchPoints = 0f;
-
- // === 属性 ===
-
- public CompProperties_PawnResearchBlueprintReader Props =>
- (CompProperties_PawnResearchBlueprintReader)this.props;
-
- public Pawn Pawn => this.parent as Pawn;
-
- ///
- /// 当前研究的科技
- ///
- public ResearchProjectDef CurrentResearch
- {
- get => currentResearch;
- private set
- {
- currentResearch = value;
- if (currentResearch != null)
- {
- // 获取当前全局进度
- currentProgress = Find.ResearchManager.GetProgress(currentResearch);
- }
- else
- {
- currentProgress = 0f;
- }
- }
- }
-
- ///
- /// 当前进度
- ///
- public float CurrentProgress => currentProgress;
-
- ///
- /// 是否正在研究中
- ///
- public bool IsResearching => isResearching && currentResearch != null && !currentResearch.IsFinished;
-
- ///
- /// 研究速度(每秒点数)
- ///
- 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;
- }
- }
-
- ///
- /// 每秒消耗的灵能科研点
- ///
- public float PsychicResearchPointsPerSecond
- {
- get
- {
- // 如果不需要灵能科研点,返回0
- if (!Props.usePsychicResearchPoints || spellHolder == null)
- return 0f;
-
- // 每研究1点需要1点灵能科研点
- return ResearchSpeedPerSecond;
- }
- }
-
- ///
- /// Pawn是否可以进行研究
- ///
- 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;
- }
- }
-
- ///
- /// 研究进度百分比(0-1)
- ///
- public float ResearchProgressPercent
- {
- get
- {
- if (currentResearch == null || currentResearch.baseCost <= 0)
- return 0f;
-
- return Mathf.Clamp01(currentProgress / currentResearch.baseCost);
- }
- }
-
- ///
- /// 剩余研究时间(秒)
- ///
- 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();
-
- // 如果自动开始研究且当前有研究项目,开始研究
- 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;
- }
- }
- }
-
- // === 研究逻辑方法 ===
-
- ///
- /// 开始研究新科技
- ///
- 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}");
- }
-
- ///
- /// 开始研究(内部方法)
- ///
- 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}");
- }
-
- ///
- /// 停止研究
- ///
- public void StopResearching()
- {
- isResearching = false;
- researchStartTick = -1;
-
- ArachnaeLog.Debug($"[PawnResearch] {Pawn?.LabelShort} 停止研究");
- }
-
- ///
- /// 更新研究进度
- ///
- 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.HasEnoughPsychicResearchPoints(pointsToAdd))
- {
- // 灵能科研点不足,停止研究
- StopResearching();
- Messages.Message(Props.researchNoPointsMessageKey.Translate(currentResearch.LabelCap),
- Pawn, MessageTypeDefOf.NegativeEvent);
- return;
- }
-
- // 消耗灵能科研点
- if (!spellHolder.ConsumePsychicResearchPoints(pointsToAdd, $"研究 {currentResearch.LabelCap}"))
- {
- // 消耗失败(理论上不应该发生,因为已经检查过了)
- StopResearching();
- return;
- }
- }
-
- // 添加到全局研究进度(在消耗成功后)
- AddResearchProgress(pointsToAdd);
-
- // 减去已添加的点数
- accumulatedResearchPoints -= pointsToAdd;
- }
-
- // 检查是否完成
- CheckResearchCompletion();
-
- // 更新上次研究时间
- lastResearchTick = Find.TickManager.TicksGame;
- }
- catch (Exception ex)
- {
- ArachnaeLog.Debug($"[PawnResearch] 更新研究进度时出错: {ex.Message}");
- StopResearching();
- }
- }
-
- ///
- /// 添加研究进度到全局
- ///
- 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);
- }
- }
-
- ///
- /// 检查研究是否完成
- ///
- private void CheckResearchCompletion()
- {
- if (currentResearch == null)
- return;
-
- if (currentResearch.IsFinished)
- {
- // 研究完成
- OnResearchCompleted();
- }
- }
-
- ///
- /// 研究完成时的处理
- ///
- 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;
- }
-
- ///
- /// 强制完成当前研究(调试用)
- ///
- 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();
- }
-
- // === 条件检查方法 ===
-
- ///
- /// 检查所有前置条件是否完成
- ///
- 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 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.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.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.Get("ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph", 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.Get("UI/Designators/Dev", false);
- debugCmd.action = delegate
- {
- ForceCompleteResearch();
- };
- yield return debugCmd;
- }
- }
-
- ///
- /// 显示研究选择菜单
- ///
- public void ShowResearchMenu()
- {
- try
- {
- // 使用指定的研究标签页
- ResearchTabDef researchTab = Props.requiredResearchTab;
- if (researchTab == null)
- {
- // 如果没有指定,使用默认的阿拉克涅科技标签页
- researchTab = DefDatabase.GetNamedSilentFail("ARA_ResearchTab");
- if (researchTab == null)
- {
- Messages.Message("ARA_PawnResearch_TabNotFound".Translate(), MessageTypeDefOf.RejectInput);
- return;
- }
- }
-
- // 获取可用的研究项目
- var availableProjects = DefDatabase.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 options = new List();
- 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 = $"{label} [{"ResearchBlueprintReader_HiddenPrerequisite".Translate()}]";
- else
- label = $"{label} [{"ResearchBlueprintReader_PrerequisitesNeeded".Translate()}]";
- }
- else if (!hasEnoughPoints)
- {
- label = $"{label} [{"ARA_PawnResearch_InsufficientPoints".Translate()}]";
- }
-
- // 创建菜单选项
- 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);
- }
- }
-
- ///
- /// 获取研究项目的工具提示
- ///
- 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}");
-
- float globalProgress = Find.ResearchManager.GetProgress(project);
- builder.AppendLine("ResearchBlueprintReader_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 missingPrereqs = new List();
-
- // 普通前置
- 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("" + "ResearchBlueprintReader_PrerequisitesNeeded".Translate() + ":");
-
- 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} [{"ResearchBlueprintReader_MissingHiddenPrerequisites".Translate()}]");
- else
- builder.AppendLine($" • {label}");
- }
- }
- }
-
- // 检查灵能科研点是否足够
- if (!hasEnoughPoints && Props.usePsychicResearchPoints && spellHolder != null)
- {
- float requiredPoints = project.baseCost - globalProgress;
- builder.AppendLine();
- builder.AppendLine("" + "ARA_PawnResearch_InsufficientPoints".Translate() + ":");
- }
-
- return builder.ToString();
- }
-
- // === 调试和信息方法 ===
-
- ///
- /// 获取研究状态描述
- ///
- 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})";
- }
-
- ///
- /// 获取调试信息
- ///
- 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();
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Gizmo_PawnResearchProgress.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Gizmo_PawnResearchProgress.cs
deleted file mode 100644
index c3bf71b..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_PawnResearchBlueprintReader/Gizmo_PawnResearchProgress.cs
+++ /dev/null
@@ -1,259 +0,0 @@
-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_NoProjectSelected".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_Gizmo_Completed".Translate();
- }
- else if (researchComp.IsResearching && researchComp.CanResearch)
- {
- GUI.color = new Color(0.5f, 0.8f, 1f);
- statusText = "ARA_PawnResearch_Gizmo_Researching".Translate();
- }
- else if (!researchComp.CanResearch)
- {
- GUI.color = new Color(0.8f, 0.2f, 0.2f);
- statusText = "ARA_PawnResearch_Gizmo_CannotResearch".Translate();
- }
- else
- {
- GUI.color = new Color(0.9f, 0.7f, 0.2f);
- statusText = "ARA_PawnResearch_Gizmo_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();
-
- if (currentResearch.IsFinished)
- {
- sb.AppendLine("" + "ARA_PawnResearch_CompletedShort".Translate() + "");
- }
- 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("" + "ARA_PawnResearch_TooltipCannotResearch".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(" • " + "ARA_NotSpawned".Translate());
- }
-
- if (researchComp.Props.usePsychicResearchPoints && researchComp.spellHolder != null)
- {
- if (researchComp.spellHolder.PsychicResearchPoints < researchComp.PsychicResearchPointsPerSecond)
- {
- sb.AppendLine(" • " + "ARA_PawnResearch_InsufficientPointsShort".Translate());
- }
- }
- }
- else
- {
- sb.AppendLine("" + "ARA_PawnResearch_TooltipPaused".Translate() + "");
- }
- }
- else
- {
- sb.AppendLine("ARA_PawnResearch_TooltipNoProject".Translate());
- }
-
- return sb.ToString().TrimEndNewlines();
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs
deleted file mode 100644
index fc4183c..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs
+++ /dev/null
@@ -1,888 +0,0 @@
-using RimWorld;
-using System.Collections.Generic;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 虫群术法持有组件 - 每个虫群单位都拥有独立的术法系统
- ///
- public class Comp_SwarmSpellHolder : ThingComp
- {
- #region 常量定义
- private const float MAX_PSYCHIC_RESEARCH = 3000f; // 灵能科研点上限固定为3000
- private const float SPELL_LEVEL_MULTIPLIER = 1f; // 术法等级,暂定为1
- private const float PSYCHIC_LOAD_PER_LEVEL = 10f; // 每级术法等级提供10点灵能负载容量
- private const int LOAD_REDUCTION_INTERVAL = 60; // 每60ticks减少1点负载
- #endregion
-
- #region 字段
- private float psychicResearchPoints = 0f; // 当前灵能科研点
- private float psychicLoad = 0f; // 当前灵能负载
- private float psychicLoadCapacity = 0f; // 灵能负载容量
- private float spellLevel = SPELL_LEVEL_MULTIPLIER; // 术法等级
-
- // 冷却系统
- private int cooldownTicksRemaining = 0; // 冷却计数器(ticks)
- private int cooldownDurationTicks = 0; // 冷却总时长(ticks)
- private bool isCooldownActive = false; // 冷却是否激活
-
- // 超载系统
- private bool isOverloaded = false; // 是否超载
- private bool limitPsychicLoadAmount = true; // 负载限制器(开启时不允许超过容量)
- private int overloadCheckTick = -1; // 上次检查超载的时间
- private const int OVERLOAD_CHECK_INTERVAL = 30; // 检查超载间隔(ticks)
-
- // 调试和状态跟踪
- private int lastUpdateTick = -1;
- private bool systemInitialized = false;
- #endregion
-
- #region 属性
- public CompProperties_SwarmSpellHolder Props => (CompProperties_SwarmSpellHolder)props;
-
- ///
- /// 当前灵能科研点
- ///
- public float PsychicResearchPoints
- {
- get => psychicResearchPoints;
- private set => psychicResearchPoints = Mathf.Clamp(value, 0f, MAX_PSYCHIC_RESEARCH);
- }
-
- ///
- /// 灵能科研点上限(固定为3000)
- ///
- public float MaxPsychicResearchPoints => MAX_PSYCHIC_RESEARCH;
-
- ///
- /// 灵能科研点百分比
- ///
- public float PsychicResearchPercent => MAX_PSYCHIC_RESEARCH > 0 ? psychicResearchPoints / MAX_PSYCHIC_RESEARCH : 0f;
-
- ///
- /// 当前灵能负载
- ///
- public float PsychicLoad
- {
- get => psychicLoad;
- private set
- {
- float oldValue = psychicLoad;
- psychicLoad = Mathf.Max(0f, value);
-
- // 检查是否进入或退出超载状态
- bool wasOverloaded = isOverloaded;
- isOverloaded = psychicLoad > psychicLoadCapacity;
-
- // 如果超载状态发生变化
- if (wasOverloaded != isOverloaded)
- {
- HandleOverloadStateChange(wasOverloaded, isOverloaded);
- }
-
- // 如果负载增加,重置冷却计时器
- if (psychicLoad > oldValue)
- {
- ResetCooldown();
- }
- }
- }
-
- ///
- /// 灵能负载容量(10 * 术法等级)
- ///
- public float PsychicLoadCapacity
- {
- get => psychicLoadCapacity;
- private set
- {
- psychicLoadCapacity = Mathf.Max(0f, value);
-
- // 重新检查超载状态
- bool wasOverloaded = isOverloaded;
- isOverloaded = psychicLoad > psychicLoadCapacity;
-
- if (wasOverloaded != isOverloaded)
- {
- HandleOverloadStateChange(wasOverloaded, isOverloaded);
- }
- }
- }
-
- ///
- /// 灵能负载百分比(用于显示,限制在100%以内)
- ///
- public float PsychicLoadPercentForDisplay
- {
- get
- {
- if (psychicLoadCapacity <= 0) return 0f;
- float percent = psychicLoad / psychicLoadCapacity;
- return Mathf.Min(1f, percent); // 最大显示为100%
- }
- }
-
- ///
- /// 实际灵能负载百分比(可能超过100%)
- ///
- public float PsychicLoadPercent => psychicLoadCapacity > 0 ? psychicLoad / psychicLoadCapacity : 0f;
-
- ///
- /// 是否超载(负载超过容量)
- ///
- public bool IsOverloaded => isOverloaded;
-
- ///
- /// 超载百分比(超过容量的部分)
- ///
- public float OverloadPercent
- {
- get
- {
- if (!isOverloaded || psychicLoadCapacity <= 0) return 0f;
- return (psychicLoad - psychicLoadCapacity) / psychicLoadCapacity;
- }
- }
-
- ///
- /// 冷却剩余时间(秒)
- ///
- public float CooldownSecondsRemaining => cooldownTicksRemaining / 60f;
-
- ///
- /// 冷却百分比
- ///
- public float CooldownPercent
- {
- get
- {
- if (cooldownDurationTicks <= 0) return 0f;
- return (float)cooldownTicksRemaining / cooldownDurationTicks;
- }
- }
-
- ///
- /// 术法等级
- ///
- public float SpellLevel
- {
- get => spellLevel;
- private set
- {
- float oldLevel = spellLevel;
- spellLevel = parent.GetStatValue(ARA_StatDefOf.ARA_SwarmSpell_Level);
-
- // 更新负载容量
- PsychicLoadCapacity = spellLevel * PSYCHIC_LOAD_PER_LEVEL;
- }
- }
-
- ///
- /// 系统是否已初始化
- ///
- public bool IsSystemInitialized => systemInitialized;
-
- ///
- /// Pawn是否可用(活着且清醒)
- ///
- public bool IsPawnAvailable
- {
- get
- {
- if (parent is Pawn pawn)
- {
- return !pawn.Dead && !pawn.Downed && pawn.Spawned;
- }
- return false;
- }
- }
-
- ///
- /// 是否冷却中
- ///
- public bool IsOnCooldown => isCooldownActive && cooldownTicksRemaining > 0;
-
- ///
- /// 是否启用负载限制器(类似原版心灵熵限制器)
- ///
- public bool LimitPsychicLoadAmount
- {
- get => limitPsychicLoadAmount;
- set => limitPsychicLoadAmount = value;
- }
- #endregion
-
- #region 生命周期方法
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
-
- // 初始化系统
- InitializeSystem();
- }
-
- public override void CompTick()
- {
- base.CompTick();
-
- // 每tick都更新冷却
- UpdateCooldownTick();
-
- // 每60ticks更新一次系统状态
- if (parent.IsHashIntervalTick(60))
- {
- UpdateSystemTick();
- }
-
- // 定期检查超载状态(更频繁的检查)
- if (Find.TickManager.TicksGame - overloadCheckTick >= OVERLOAD_CHECK_INTERVAL)
- {
- CheckOverloadStatus();
- overloadCheckTick = Find.TickManager.TicksGame;
- }
- }
-
- public override void PostExposeData()
- {
- base.PostExposeData();
-
- // 序列化所有数据
- Scribe_Values.Look(ref psychicResearchPoints, "psychicResearchPoints", 0f);
- Scribe_Values.Look(ref psychicLoad, "psychicLoad", 0f);
- Scribe_Values.Look(ref psychicLoadCapacity, "psychicLoadCapacity", 0f);
- Scribe_Values.Look(ref spellLevel, "spellLevel", SPELL_LEVEL_MULTIPLIER);
- Scribe_Values.Look(ref systemInitialized, "systemInitialized", false);
- Scribe_Values.Look(ref lastUpdateTick, "lastUpdateTick", -1);
-
- // 冷却系统
- Scribe_Values.Look(ref cooldownTicksRemaining, "cooldownTicksRemaining", 0);
- Scribe_Values.Look(ref cooldownDurationTicks, "cooldownDurationTicks", 0);
- Scribe_Values.Look(ref isCooldownActive, "isCooldownActive", false);
-
- // 超载系统
- Scribe_Values.Look(ref isOverloaded, "isOverloaded", false);
- Scribe_Values.Look(ref overloadCheckTick, "overloadCheckTick", -1);
- Scribe_Values.Look(ref limitPsychicLoadAmount, "limitPsychicLoadAmount", true);
-
- if (Scribe.mode == LoadSaveMode.LoadingVars)
- {
- // 加载后重新计算负载容量以确保一致性
- if (psychicLoadCapacity <= 0)
- {
- psychicLoadCapacity = spellLevel * PSYCHIC_LOAD_PER_LEVEL;
- }
-
- // 重新检查超载状态
- CheckOverloadStatus();
- }
- }
- #endregion
-
- #region 初始化方法
- ///
- /// 初始化术法系统
- ///
- private void InitializeSystem()
- {
- if (systemInitialized)
- return;
-
- // 设置初始值
- spellLevel = parent.GetStatValue(ARA_StatDefOf.ARA_SwarmSpell_Level);
- psychicLoadCapacity = spellLevel * PSYCHIC_LOAD_PER_LEVEL;
- psychicLoad = 0f;
- psychicResearchPoints = 0f;
-
- // 初始化冷却系统
- cooldownTicksRemaining = 0;
- cooldownDurationTicks = 0;
- isCooldownActive = false;
-
- // 初始化超载系统
- isOverloaded = false;
- overloadCheckTick = Find.TickManager.TicksGame;
-
- systemInitialized = true;
- lastUpdateTick = Find.TickManager.TicksGame;
- }
-
- ///
- /// 重置术法系统
- ///
- public void ResetSystem()
- {
- psychicResearchPoints = 0f;
- psychicLoad = 0f;
- psychicLoadCapacity = spellLevel * PSYCHIC_LOAD_PER_LEVEL;
-
- // 重置冷却
- cooldownTicksRemaining = 0;
- cooldownDurationTicks = 0;
- isCooldownActive = false;
-
- // 重置超载
- isOverloaded = false;
- RemoveOverdriveHediff();
-
- systemInitialized = false;
- }
- #endregion
-
- #region 冷却系统
- ///
- /// 重置冷却计时器
- ///
- private void ResetCooldown()
- {
- if (!IsSystemInitialized || !IsPawnAvailable)
- return;
-
- // 读取ARA_SwarmSpell_Cooldown_Delay stat(单位:秒)
- Pawn pawn = parent as Pawn;
- if (pawn == null) return;
-
- float cooldownDelaySeconds = pawn.GetStatValue(ARA_StatDefOf.ARA_SwarmSpell_Cooldown_Delay);
- cooldownDurationTicks = Mathf.RoundToInt(cooldownDelaySeconds * 60f); // 转换为ticks
- cooldownTicksRemaining = cooldownDurationTicks;
- isCooldownActive = true;
- }
-
- ///
- /// 每tick更新冷却
- ///
- private void UpdateCooldownTick()
- {
- if (!IsSystemInitialized || !IsPawnAvailable)
- return;
-
- // 如果没有冷却中,或者超载状态下冷却锁定,则不处理
- if (!isCooldownActive || cooldownTicksRemaining <= 0 || isOverloaded)
- return;
-
- // 减少冷却时间
- cooldownTicksRemaining--;
-
- // 如果冷却结束
- if (cooldownTicksRemaining <= 0)
- {
- cooldownTicksRemaining = 0;
- isCooldownActive = false;
- }
- }
-
- ///
- /// 自动减少灵能负载(当冷却结束时)
- ///
- private void ReduceLoadAfterCooldown()
- {
- if (!IsSystemInitialized || !IsPawnAvailable || isOverloaded)
- return;
-
- // 每60ticks减少1点负载
- if (Find.TickManager.TicksGame % LOAD_REDUCTION_INTERVAL == 0)
- {
- // 只减少1点
- if (psychicLoad > 0)
- {
- PsychicLoad = Mathf.Max(0f, psychicLoad - 1f);
-
- // 如果还有负载,重新激活冷却
- if (psychicLoad > 0)
- {
- ResetCooldown();
- }
- }
- }
- }
-
- ///
- /// 获取冷却状态描述
- ///
- public string GetCooldownStatus()
- {
- if (!isCooldownActive || cooldownTicksRemaining <= 0)
- return "冷却完成";
-
- return $"冷却中: {CooldownSecondsRemaining:F1}秒 ({CooldownPercent:P0})";
- }
- #endregion
-
- #region 超载系统
- ///
- /// 处理超载状态变化
- ///
- private void HandleOverloadStateChange(bool wasOverloaded, bool nowOverloaded)
- {
- Pawn pawn = parent as Pawn;
- if (pawn == null) return;
-
- if (nowOverloaded && !wasOverloaded)
- {
- // 进入超载状态
- AddOverdriveHediff();
- }
- else if (!nowOverloaded && wasOverloaded)
- {
- // 退出超载状态
- RemoveOverdriveHediff();
- }
- }
-
- ///
- /// 添加超载Hediff
- ///
- private void AddOverdriveHediff()
- {
- Pawn pawn = parent as Pawn;
- if (pawn == null || pawn.Dead || pawn.Downed) return;
-
- HediffDef overdriveDef = ARA_HediffDefOf.ARA_SwarmSpell_Overdrive;
- if (overdriveDef == null)
- {
- Log.Warning("[虫群术法] 未找到ARA_SwarmSpell_Overdrive Hediff定义");
- return;
- }
-
- // 添加或更新超载Hediff
- Hediff overdriveHediff = pawn.health.hediffSet.GetFirstHediffOfDef(overdriveDef);
- if (overdriveHediff == null)
- {
- overdriveHediff = HediffMaker.MakeHediff(overdriveDef, pawn);
- pawn.health.AddHediff(overdriveHediff);
- }
- }
-
- ///
- /// 移除超载Hediff
- ///
- private void RemoveOverdriveHediff()
- {
- Pawn pawn = parent as Pawn;
- if (pawn == null || pawn.Dead || pawn.Downed) return;
-
- HediffDef overdriveDef = ARA_HediffDefOf.ARA_SwarmSpell_Overdrive;
- if (overdriveDef == null) return;
-
- Hediff overdriveHediff = pawn.health.hediffSet.GetFirstHediffOfDef(overdriveDef);
- if (overdriveHediff != null)
- {
- pawn.health.RemoveHediff(overdriveHediff);
- }
- }
-
- ///
- /// 定期检查超载状态
- ///
- private void CheckOverloadStatus()
- {
- if (!IsSystemInitialized || !IsPawnAvailable)
- return;
-
- Pawn pawn = parent as Pawn;
- if (pawn == null) return;
-
- // 检查当前是否应该处于超载状态
- bool shouldBeOverloaded = psychicLoad > psychicLoadCapacity;
-
- // 如果状态不一致,更新
- if (shouldBeOverloaded != isOverloaded)
- {
- isOverloaded = shouldBeOverloaded;
- HandleOverloadStateChange(!shouldBeOverloaded, shouldBeOverloaded);
- }
-
- // 如果处于超载状态,确保Hediff存在
- if (isOverloaded)
- {
- HediffDef overdriveDef = ARA_HediffDefOf.ARA_SwarmSpell_Overdrive;
- if (overdriveDef != null)
- {
- Hediff overdriveHediff = pawn.health.hediffSet.GetFirstHediffOfDef(overdriveDef);
- if (overdriveHediff == null)
- {
- // Hediff丢失,重新添加
- AddOverdriveHediff();
- }
- }
- }
- }
-
- ///
- /// 强制退出超载状态(通过外部方法降低负载时调用)
- ///
- public void ForceExitOverload()
- {
- if (!isOverloaded) return;
-
- // 确保负载不超过容量
- if (psychicLoad > psychicLoadCapacity)
- {
- psychicLoad = psychicLoadCapacity;
- }
-
- // 更新状态
- isOverloaded = false;
- RemoveOverdriveHediff();
- }
- #endregion
-
- #region 公开方法 - 灵能科研点操作
- ///
- /// 获取当前灵能科研点
- ///
- public float GetPsychicResearchPoints()
- {
- return psychicResearchPoints;
- }
-
- ///
- /// 设置灵能科研点
- ///
- public bool SetPsychicResearchPoints(float value, string reason = "")
- {
- if (!IsSystemInitialized || value < 0f)
- return false;
-
- float oldValue = psychicResearchPoints;
- psychicResearchPoints = Mathf.Clamp(value, 0f, MAX_PSYCHIC_RESEARCH);
-
- return true;
- }
-
- ///
- /// 增加灵能科研点
- ///
- public bool AddPsychicResearchPoints(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f)
- return false;
-
- float oldValue = psychicResearchPoints;
- psychicResearchPoints = Mathf.Min(psychicResearchPoints + amount, MAX_PSYCHIC_RESEARCH);
-
- return true;
- }
-
- ///
- /// 消耗灵能科研点
- ///
- public bool ConsumePsychicResearchPoints(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f || psychicResearchPoints < amount)
- return false;
-
- float oldValue = psychicResearchPoints;
- psychicResearchPoints -= amount;
-
- return true;
- }
-
- ///
- /// 检查是否有足够的灵能科研点
- ///
- public bool HasEnoughPsychicResearchPoints(float requiredAmount)
- {
- return IsSystemInitialized && psychicResearchPoints >= requiredAmount;
- }
-
- ///
- /// 获取剩余科研点容量
- ///
- public float GetRemainingResearchCapacity()
- {
- return MAX_PSYCHIC_RESEARCH - psychicResearchPoints;
- }
- #endregion
-
- #region 公开方法 - 灵能负载操作
- ///
- /// 获取当前灵能负载
- ///
- public float GetPsychicLoad()
- {
- return psychicLoad;
- }
-
- ///
- /// 获取灵能负载容量
- ///
- public float GetPsychicLoadCapacity()
- {
- return psychicLoadCapacity;
- }
-
- ///
- /// 设置灵能负载
- ///
- public bool SetPsychicLoad(float value, string reason = "")
- {
- if (!IsSystemInitialized || value < 0f)
- return false;
-
- PsychicLoad = value;
- return true;
- }
-
- ///
- /// 增加灵能负载(可以超过容量)
- ///
- public bool AddPsychicLoad(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f)
- return false;
-
- float oldValue = psychicLoad;
- PsychicLoad = psychicLoad + amount;
-
- return true;
- }
-
- ///
- /// 减少灵能负载
- ///
- public bool ReducePsychicLoad(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f)
- return false;
-
- float oldValue = psychicLoad;
- PsychicLoad = Mathf.Max(0f, psychicLoad - amount);
-
- // 如果减少负载后退出超载状态,可能需要特殊处理
- if (isOverloaded && psychicLoad <= psychicLoadCapacity)
- {
- ForceExitOverload();
- }
-
- return true;
- }
-
- ///
- /// 检查是否有足够的灵能负载容量(不考虑超载)
- ///
- public bool HasEnoughPsychicLoadCapacity(float requiredAmount)
- {
- return IsSystemInitialized && (psychicLoadCapacity - psychicLoad) >= requiredAmount;
- }
-
- ///
- /// 获取剩余负载容量(不考虑超载)
- ///
- public float GetRemainingLoadCapacity()
- {
- return psychicLoadCapacity - psychicLoad;
- }
-
- ///
- /// 获取实际剩余负载容量(考虑当前负载,可以为负数表示超载)
- ///
- public float GetActualRemainingLoadCapacity()
- {
- return psychicLoadCapacity - psychicLoad;
- }
- #endregion
-
- #region 公开方法 - 术法等级操作
- ///
- /// 获取当前术法等级
- ///
- public float GetSpellLevel()
- {
- return parent.GetStatValue(ARA_StatDefOf.ARA_SwarmSpell_Level);
- }
-
- ///
- /// 设置术法等级
- ///
- public bool SetSpellLevel(float level, string reason = "")
- {
- if (!IsSystemInitialized || level < 0f)
- return false;
-
- float oldLevel = spellLevel;
- SpellLevel = level;
-
- return true;
- }
-
- ///
- /// 增加术法等级
- ///
- public bool IncreaseSpellLevel(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f)
- return false;
-
- float oldLevel = spellLevel;
- SpellLevel = spellLevel + amount;
-
- return true;
- }
-
- ///
- /// 减少术法等级
- ///
- public bool DecreaseSpellLevel(float amount, string reason = "")
- {
- if (!IsSystemInitialized || amount <= 0f)
- return false;
-
- float oldLevel = spellLevel;
- SpellLevel = Mathf.Max(0f, spellLevel - amount);
-
- return true;
- }
- #endregion
-
- #region 状态检查和更新
- ///
- /// 定期更新系统
- ///
- private void UpdateSystemTick()
- {
- if (!IsSystemInitialized || !IsPawnAvailable)
- return;
-
- lastUpdateTick = Find.TickManager.TicksGame;
-
- // 如果冷却结束且没有超载,自动减少负载
- if (!isCooldownActive && !isOverloaded && psychicLoad > 0)
- {
- ReduceLoadAfterCooldown();
- }
-
- // 这里可以添加其他自动恢复逻辑
- }
-
- ///
- /// 获取系统状态描述
- ///
- public string GetSystemStatus()
- {
- string status = $"虫群术法系统 - {parent.LabelCap}\n" +
- $"术法等级: {spellLevel:F1}\n" +
- $"灵能负载: {psychicLoad:F1}/{psychicLoadCapacity:F1} ({PsychicLoadPercent:P1})";
-
- if (isOverloaded)
- {
- status += $" [超载: +{OverloadPercent:P0}]";
- }
-
- status += $"\n灵能科研: {psychicResearchPoints:F1}/{MAX_PSYCHIC_RESEARCH:F0} ({PsychicResearchPercent:P1})";
-
- if (IsOnCooldown)
- {
- status += $"\n冷却: {CooldownSecondsRemaining:F1}秒";
- }
-
- return status;
- }
-
- ///
- /// 获取调试信息
- ///
- public string GetDebugInfo()
- {
- return $"=== 虫群术法调试信息 ===\n" +
- $"单位: {parent.LabelCap}\n" +
- $"术法等级: {spellLevel:F1}\n" +
- $"负载容量: {psychicLoadCapacity:F1} (10 * 等级)\n" +
- $"当前负载: {psychicLoad:F1}\n" +
- $"负载百分比: {PsychicLoadPercent:P1}\n" +
- $"超载状态: {isOverloaded}\n" +
- $"超载百分比: {OverloadPercent:P1}\n" +
- $"冷却状态: {IsOnCooldown}\n" +
- $"冷却剩余: {cooldownTicksRemaining} ticks ({CooldownSecondsRemaining:F1}秒)\n" +
- $"科研点: {psychicResearchPoints:F1}/{MAX_PSYCHIC_RESEARCH:F0}\n" +
- $"科研百分比: {PsychicResearchPercent:P1}\n" +
- $"最后更新: {lastUpdateTick}\n" +
- $"系统初始化: {systemInitialized}\n" +
- $"Pawn可用: {IsPawnAvailable}";
- }
- #endregion
-
- #region Gizmo 方法
- ///
- /// 获取术法系统的Gizmo
- ///
- public override IEnumerable CompGetGizmosExtra()
- {
- foreach (Gizmo gizmo in base.CompGetGizmosExtra())
- {
- yield return gizmo;
- }
-
- // 只有拥有此组件的虫群单位才显示术法Gizmo
- if (IsSystemInitialized && parent.Faction == Faction.OfPlayer && parent is Pawn)
- {
- var spellGizmo = new Gizmo_SwarmSpellStatus(this);
- if (spellGizmo.ShouldDisplay())
- {
- yield return spellGizmo;
- }
-
- // 调试Gizmo
- if (DebugSettings.godMode)
- {
- yield return new Command_Action
- {
- defaultLabel = "[调试] 重置术法系统",
- defaultDesc = "重置所有术法数值",
- icon = ContentFinder.Get("UI/Commands/Detonate", false),
- action = () => ResetSystem()
- };
-
- yield return new Command_Action
- {
- defaultLabel = "[调试] 增加科研点(100)",
- defaultDesc = "增加100灵能科研点",
- icon = ContentFinder.Get("UI/Commands/Research", false),
- action = () => AddPsychicResearchPoints(100f, "调试")
- };
-
- yield return new Command_Action
- {
- defaultLabel = "[调试] 增加负载(5)",
- defaultDesc = "增加5点灵能负载",
- icon = ContentFinder.Get("UI/Commands/Attack", false),
- action = () => AddPsychicLoad(5f, "调试")
- };
-
- yield return new Command_Action
- {
- defaultLabel = "[调试] 减少负载(5)",
- defaultDesc = "减少5点灵能负载",
- icon = ContentFinder.Get("UI/Commands/Relax", false),
- action = () => ReducePsychicLoad(5f, "调试")
- };
-
- yield return new Command_Action
- {
- defaultLabel = "[调试] 增加术法等级(0.5)",
- defaultDesc = "增加0.5级术法等级",
- icon = ContentFinder.Get("UI/Commands/Upgrade", false),
- action = () => IncreaseSpellLevel(0.5f, "调试")
- };
- }
- }
- }
- #endregion
- }
-
- ///
- /// CompProperties for Comp_SwarmSpellHolder
- ///
- public class CompProperties_SwarmSpellHolder : CompProperties
- {
- // 可以在这里添加配置选项,例如:
- // public float initialSpellLevel = 1f;
- // public bool enableAutoRecovery = false;
-
- public CompProperties_SwarmSpellHolder()
- {
- compClass = typeof(Comp_SwarmSpellHolder);
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Gizmo_SwarmSpellStatus.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Gizmo_SwarmSpellStatus.cs
deleted file mode 100644
index ed3543d..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Gizmo_SwarmSpellStatus.cs
+++ /dev/null
@@ -1,358 +0,0 @@
-using RimWorld;
-using System.Text;
-using UnityEngine;
-using Verse;
-using Verse.Sound;
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public class Gizmo_SwarmSpellStatus : Gizmo
- {
- private readonly Comp_SwarmSpellHolder spellHolder;
-
- private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.15f, 0.15f, 0.15f));
- private static readonly Texture2D LoadBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.46f, 0.34f, 0.35f));
- private static readonly Texture2D OverLimitBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.72f, 0.25f, 0.25f));
- private static readonly Texture2D LoadAddPreviewTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.78f, 0.72f, 0.66f));
- private static readonly Texture2D ResearchBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.32f, 0.47f, 0.7f));
- private static readonly Texture2D ThresholdTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.7f));
- private static readonly Texture2D LimitedTex = ContentFinder.Get("UI/Icons/EntropyLimit/Limited", false);
- private static readonly Texture2D UnlimitedTex = ContentFinder.Get("UI/Icons/EntropyLimit/Unlimited", false);
-
- private const float GizmoWidth = 212f;
- private const float GizmoHeight = 75f;
- private const float Padding = 6f;
-
- public Gizmo_SwarmSpellStatus(Comp_SwarmSpellHolder holder)
- {
- spellHolder = holder;
- Order = -95f;
- }
-
- public override float GetWidth(float maxWidth)
- {
- return GizmoWidth;
- }
-
- public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
- {
- if (spellHolder == null || !spellHolder.IsSystemInitialized)
- {
- return new GizmoResult(GizmoState.Clear);
- }
-
- Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), GizmoHeight);
- Rect contentRect = rect.ContractedBy(Padding);
- Widgets.DrawWindowBackground(rect);
-
- Command_Ability hoveredAbility = MapGizmoUtility.LastMouseOverGizmo as Command_Ability;
- FloatRange hoveredLoadRange = default;
- bool hasHoveredLoad = TryGetHoveredAbilityLoadRange(hoveredAbility, out hoveredLoadRange);
-
- DrawLabels(contentRect);
- Rect loadBarRect = new Rect(contentRect.x + 63f, contentRect.y + 6f, 100f, 22f);
- Rect researchBarRect = new Rect(contentRect.x + 63f, contentRect.y + 38f, 100f, 22f);
-
- DrawLoadBar(loadBarRect, hasHoveredLoad ? hoveredLoadRange : default, hasHoveredLoad);
- DrawResearchBar(researchBarRect);
- DrawLimiterToggle(contentRect);
-
- TooltipHandler.TipRegion(loadBarRect, new TipSignal(GenerateLoadTooltip(hasHoveredLoad ? hoveredLoadRange : default, hasHoveredLoad), 43502));
- TooltipHandler.TipRegion(researchBarRect, new TipSignal(GenerateResearchTooltip(), 43501));
- TooltipHandler.TipRegion(rect, new TipSignal(GenerateBasicTooltip(), 43500));
-
- return new GizmoResult(GizmoState.Clear);
- }
-
- private void DrawLabels(Rect contentRect)
- {
- Text.Font = GameFont.Small;
- Text.Anchor = TextAnchor.UpperLeft;
-
- Rect loadLabelRect = new Rect(contentRect.x, contentRect.y + 6f, 62f, Text.LineHeight);
- Rect researchLabelRect = new Rect(contentRect.x, contentRect.y + 38f, 62f, Text.LineHeight);
-
- Widgets.Label(loadLabelRect, "ARA_SwarmSpell_Load_Title".Translate());
- Widgets.Label(researchLabelRect, "ARA_SwarmSpell_Research_Title".Translate());
- }
-
- private void DrawLoadBar(Rect loadBarRect, FloatRange hoveredLoadRange, bool hasHoveredLoad)
- {
- float loadRelative = LoadToRelativeValue(spellHolder.PsychicLoad, spellHolder.PsychicLoadCapacity);
- Widgets.FillableBar(loadBarRect, Mathf.Min(loadRelative, 1f), LoadBarTex, EmptyBarTex, doBorder: true);
-
- if (loadRelative > 1f)
- {
- Widgets.FillableBar(loadBarRect, Mathf.Min(loadRelative - 1f, 1f), OverLimitBarTex, LoadBarTex, doBorder: true);
- }
-
- if (hasHoveredLoad && hoveredLoadRange.max > float.Epsilon)
- {
- DrawLoadPreview(loadBarRect, loadRelative, hoveredLoadRange.max);
- }
-
- if (loadRelative > 1f)
- {
- float overloadRelative = loadRelative - 1f;
- DrawThreshold(loadBarRect, 0.33f, overloadRelative);
- DrawThreshold(loadBarRect, 0.66f, overloadRelative);
- }
-
- string loadText;
- if (spellHolder.IsOverloaded)
- {
- loadText = "ARA_SwarmSpell_Load_Overload".Translate(
- spellHolder.PsychicLoad.ToString("F1"),
- spellHolder.PsychicLoadCapacity.ToString("F1"),
- spellHolder.OverloadPercent.ToString("P0"));
- }
- else
- {
- loadText = "ARA_SwarmSpell_Load".Translate(
- spellHolder.PsychicLoad.ToString("F1"),
- spellHolder.PsychicLoadCapacity.ToString("F1"));
- }
-
- Text.Anchor = TextAnchor.MiddleCenter;
- Widgets.Label(loadBarRect, loadText);
- Text.Anchor = TextAnchor.UpperLeft;
- }
-
- private void DrawLoadPreview(Rect loadBarRect, float currentRelative, float addedLoad)
- {
- float predictedRelative = LoadToRelativeValue(spellHolder.PsychicLoad + addedLoad, spellHolder.PsychicLoadCapacity);
- Rect previewRect = loadBarRect.ContractedBy(3f);
- float width = previewRect.width;
-
- float from = currentRelative;
- float to = predictedRelative;
-
- if (from > 1f)
- {
- from -= 1f;
- to -= 1f;
- }
-
- previewRect.xMin = previewRect.xMin + Mathf.Clamp01(from) * width;
- previewRect.width = Mathf.Max(Mathf.Min(to, 1f) - Mathf.Clamp01(from), 0f) * width;
-
- if (previewRect.width > 0f)
- {
- GUI.color = new Color(1f, 1f, 1f, PulsingAlpha() * 0.7f);
- GenUI.DrawTextureWithMaterial(previewRect, LoadAddPreviewTex, null);
- GUI.color = Color.white;
- }
- }
-
- private void DrawThreshold(Rect rect, float percent, float currentOverloadRelative)
- {
- if (currentOverloadRelative < percent)
- {
- return;
- }
-
- Rect thresholdRect = new Rect(rect.x + rect.width * percent - 1f, rect.y + 2f, 2f, rect.height - 4f);
- GUI.DrawTexture(thresholdRect, ThresholdTex);
- }
-
- private void DrawResearchBar(Rect researchBarRect)
- {
- float researchPercent = Mathf.Clamp01(spellHolder.PsychicResearchPercent);
- Widgets.FillableBar(researchBarRect, researchPercent, ResearchBarTex, EmptyBarTex, doBorder: true);
-
- Text.Anchor = TextAnchor.MiddleCenter;
- Widgets.Label(researchBarRect, "ARA_SwarmSpell_Research".Translate(
- spellHolder.PsychicResearchPoints.ToString("F0"),
- spellHolder.MaxPsychicResearchPoints.ToString("F0")));
- Text.Anchor = TextAnchor.UpperLeft;
- }
-
- private void DrawLimiterToggle(Rect contentRect)
- {
- float buttonSize = 24f;
- Rect buttonRect = new Rect(contentRect.x + contentRect.width - buttonSize, contentRect.y + contentRect.height / 2f - buttonSize / 2f, buttonSize, buttonSize);
-
- Texture2D buttonTexture = spellHolder.LimitPsychicLoadAmount ? LimitedTex : UnlimitedTex;
- if (buttonTexture == null)
- {
- buttonTexture = BaseContent.BadTex;
- }
-
- if (Widgets.ButtonImage(buttonRect, buttonTexture))
- {
- spellHolder.LimitPsychicLoadAmount = !spellHolder.LimitPsychicLoadAmount;
- if (spellHolder.LimitPsychicLoadAmount)
- {
- SoundDefOf.Tick_Low.PlayOneShotOnCamera();
- }
- else
- {
- SoundDefOf.Tick_High.PlayOneShotOnCamera();
- }
- }
-
- TooltipHandler.TipRegion(buttonRect, "PawnTooltipPsychicEntropyLimit".Translate());
- }
-
- private bool TryGetHoveredAbilityLoadRange(Command_Ability command, out FloatRange loadRange)
- {
- loadRange = default;
- if (command?.Ability == null)
- {
- return false;
- }
-
- if (command.Ability.pawn != spellHolder.parent)
- {
- return false;
- }
-
- float min = 0f;
- float max = 0f;
- bool foundAny = false;
-
- foreach (CompAbilityEffect_PsychicLoadCost loadComp in command.Ability.CompsOfType())
- {
- foundAny = true;
- if (loadComp.Props.useFixedCost)
- {
- min += loadComp.Props.fixedLoadCost;
- max += loadComp.Props.fixedLoadCost;
- }
- else
- {
- min += loadComp.Props.loadCostRange.min;
- max += loadComp.Props.loadCostRange.max;
- }
- }
-
- if (!foundAny)
- {
- return false;
- }
-
- loadRange = new FloatRange(min, max);
- return true;
- }
-
- private string GenerateResearchTooltip()
- {
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("ARA_SwarmSpell_Research_Title".Translate().Colorize(ColoredText.TipSectionTitleColor));
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Research_Current".Translate(
- spellHolder.PsychicResearchPoints.ToString("F0"),
- spellHolder.MaxPsychicResearchPoints.ToString("F0")));
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Research_Description".Translate().Colorize(ColoredText.TipSectionTitleColor));
- sb.AppendLine("ARA_SwarmSpell_Research_DescriptionText".Translate());
- return sb.ToString();
- }
-
- private string GenerateLoadTooltip(FloatRange hoveredLoadRange, bool hasHoveredLoad)
- {
- StringBuilder sb = new StringBuilder();
-
- if (spellHolder.IsOverloaded)
- {
- sb.AppendLine("ARA_SwarmSpell_Load_Title".Translate().Colorize(Color.red));
- }
- else
- {
- sb.AppendLine("ARA_SwarmSpell_Load_Title".Translate().Colorize(ColoredText.TipSectionTitleColor));
- }
-
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Load_Current".Translate(
- spellHolder.PsychicLoad.ToString("F1"),
- spellHolder.PsychicLoadCapacity.ToString("F1")));
-
- if (hasHoveredLoad && hoveredLoadRange.max > float.Epsilon)
- {
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_LoadCost".Translate().Colorize(ColoredText.TipSectionTitleColor));
- if (Mathf.Abs(hoveredLoadRange.max - hoveredLoadRange.min) < 0.01f)
- {
- sb.AppendLine("ARA_SwarmSpell_LoadCost_Fixed".Translate(hoveredLoadRange.max.ToString("F1")));
- }
- else
- {
- sb.AppendLine("ARA_SwarmSpell_LoadCost_Range".Translate(
- hoveredLoadRange.min.ToString("F1"),
- hoveredLoadRange.max.ToString("F1")));
- }
- }
-
- if (spellHolder.IsOverloaded)
- {
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Load_OverloadWarning".Translate().Colorize(Color.red));
- }
-
- if (spellHolder.IsOnCooldown)
- {
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Cooldown_Status".Translate().Colorize(ColoredText.TipSectionTitleColor));
- sb.AppendLine("ARA_SwarmSpell_Cooldown_Remaining".Translate(spellHolder.CooldownSecondsRemaining.ToString("F1")));
- }
-
- sb.AppendLine();
- string limiterState = spellHolder.LimitPsychicLoadAmount ? "On".Translate() : "Off".Translate();
- sb.AppendLine($"负载限制器: {limiterState}".Colorize(ColoredText.TipSectionTitleColor));
- sb.AppendLine("PawnTooltipPsychicEntropyLimit".Translate());
-
- return sb.ToString();
- }
-
- private string GenerateBasicTooltip()
- {
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("ARA_SwarmSpell_Gizmo_Title".Translate().Colorize(ColoredText.TipSectionTitleColor));
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Gizmo_Desc".Translate());
- sb.AppendLine();
- sb.AppendLine("ARA_SwarmSpell_Gizmo_Hint".Translate());
- return sb.ToString();
- }
-
- private static float LoadToRelativeValue(float load, float capacity)
- {
- if (load <= float.Epsilon || capacity <= float.Epsilon)
- {
- return 0f;
- }
-
- if (load <= capacity)
- {
- return load / capacity;
- }
-
- return 1f + (load - capacity) / capacity;
- }
-
- private static float PulsingAlpha()
- {
- float cycle = Mathf.Repeat(Time.time, 0.85f);
- if (cycle < 0.1f)
- {
- return cycle / 0.1f;
- }
-
- if (cycle >= 0.25f)
- {
- return 1f - (cycle - 0.25f) / 0.6f;
- }
-
- return 1f;
- }
-
- public bool ShouldDisplay()
- {
- return spellHolder != null &&
- spellHolder.IsSystemInitialized &&
- spellHolder.parent is Pawn &&
- spellHolder.parent.Faction == Faction.OfPlayer;
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/SwarmSpellUtility.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/SwarmSpellUtility.cs
deleted file mode 100644
index d01faf9..0000000
--- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/SwarmSpellUtility.cs
+++ /dev/null
@@ -1,439 +0,0 @@
-using RimWorld;
-using System.Collections.Generic;
-using System.Linq;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- ///
- /// 虫群术法系统工具类
- ///
- public static class SwarmSpellUtility
- {
- #region 常量定义
- public const float MAX_PSYCHIC_RESEARCH = 3000f;
- public const float BASE_SPELL_LEVEL = 1f;
- public const float PSYCHIC_LOAD_PER_LEVEL = 10f;
- #endregion
-
- #region 术法组件查找
- ///
- /// 获取Pawn的术法持有组件
- ///
- public static Comp_SwarmSpellHolder GetSpellHolder(Pawn pawn)
- {
- if (pawn == null || pawn.Destroyed)
- return null;
-
- return pawn.TryGetComp();
- }
-
- ///
- /// 检查Pawn是否有术法组件
- ///
- public static bool HasSpellHolder(Pawn pawn)
- {
- return GetSpellHolder(pawn) != null;
- }
-
- ///
- /// 获取所有拥有术法组件的虫群单位
- ///
- public static IEnumerable GetAllSpellHolders()
- {
- if (Current.Game == null)
- yield break;
-
- foreach (Map map in Current.Game.Maps)
- {
- foreach (Pawn pawn in map.mapPawns.AllPawns)
- {
- if (HasSpellHolder(pawn))
- {
- yield return pawn;
- }
- }
- }
- }
-
- ///
- /// 获取玩家派系中拥有术法组件的虫群单位数量
- ///
- public static int CountPlayerSpellHolders()
- {
- return GetAllSpellHolders().Count(p => p.Faction == Faction.OfPlayer);
- }
- #endregion
-
- #region 灵能科研点操作
- ///
- /// 获取灵能科研点
- ///
- public static float GetPsychicResearchPoints(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetPsychicResearchPoints() ?? 0f;
- }
-
- ///
- /// 设置灵能科研点
- ///
- public static bool SetPsychicResearchPoints(Pawn pawn, float value, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.SetPsychicResearchPoints(value, reason) ?? false;
- }
-
- ///
- /// 增加灵能科研点
- ///
- public static bool AddPsychicResearchPoints(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.AddPsychicResearchPoints(amount, reason) ?? false;
- }
-
- ///
- /// 消耗灵能科研点
- ///
- public static bool ConsumePsychicResearchPoints(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.ConsumePsychicResearchPoints(amount, reason) ?? false;
- }
-
- ///
- /// 检查是否有足够的灵能科研点
- ///
- public static bool HasEnoughPsychicResearchPoints(Pawn pawn, float requiredAmount)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.HasEnoughPsychicResearchPoints(requiredAmount) ?? false;
- }
-
- ///
- /// 批量增加灵能科研点(给多个单位)
- ///
- public static void AddPsychicResearchPointsToAll(IEnumerable pawns, float amount, string reason = "")
- {
- int successCount = 0;
- foreach (var pawn in pawns)
- {
- if (AddPsychicResearchPoints(pawn, amount, reason))
- {
- successCount++;
- }
- }
- }
- #endregion
-
- #region 灵能负载操作
- ///
- /// 获取灵能负载
- ///
- public static float GetPsychicLoad(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetPsychicLoad() ?? 0f;
- }
-
- ///
- /// 获取灵能负载容量
- ///
- public static float GetPsychicLoadCapacity(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetPsychicLoadCapacity() ?? 0f;
- }
-
- ///
- /// 设置灵能负载
- ///
- public static bool SetPsychicLoad(Pawn pawn, float value, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.SetPsychicLoad(value, reason) ?? false;
- }
-
- ///
- /// 增加灵能负载
- ///
- public static bool AddPsychicLoad(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.AddPsychicLoad(amount, reason) ?? false;
- }
-
- ///
- /// 减少灵能负载
- ///
- public static bool ReducePsychicLoad(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.ReducePsychicLoad(amount, reason) ?? false;
- }
-
- ///
- /// 检查是否有足够的灵能负载容量
- ///
- public static bool HasEnoughPsychicLoadCapacity(Pawn pawn, float requiredAmount)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.HasEnoughPsychicLoadCapacity(requiredAmount) ?? false;
- }
-
- ///
- /// 获取负载百分比
- ///
- public static float GetPsychicLoadPercent(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.PsychicLoadPercent ?? 0f;
- }
- #endregion
-
- #region 术法等级操作
- ///
- /// 获取术法等级
- ///
- public static float GetSpellLevel(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetSpellLevel() ?? 0f;
- }
-
- ///
- /// 设置术法等级
- ///
- public static bool SetSpellLevel(Pawn pawn, float level, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.SetSpellLevel(level, reason) ?? false;
- }
-
- ///
- /// 增加术法等级
- ///
- public static bool IncreaseSpellLevel(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.IncreaseSpellLevel(amount, reason) ?? false;
- }
-
- ///
- /// 减少术法等级
- ///
- public static bool DecreaseSpellLevel(Pawn pawn, float amount, string reason = "")
- {
- var holder = GetSpellHolder(pawn);
- return holder?.DecreaseSpellLevel(amount, reason) ?? false;
- }
-
- ///
- /// 批量增加术法等级(给多个单位)
- ///
- public static void IncreaseSpellLevelForAll(IEnumerable pawns, float amount, string reason = "")
- {
- int successCount = 0;
- foreach (var pawn in pawns)
- {
- if (IncreaseSpellLevel(pawn, amount, reason))
- {
- successCount++;
- }
- }
- }
- #endregion
-
- #region 状态检查
- ///
- /// 检查术法系统是否可用
- ///
- public static bool IsSpellSystemAvailable(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder != null && holder.IsSystemInitialized && holder.IsPawnAvailable;
- }
-
- ///
- /// 检查是否过载(负载超过80%)
- ///
- public static bool IsOverloaded(Pawn pawn)
- {
- float loadPercent = GetPsychicLoadPercent(pawn);
- return loadPercent > 0.8f;
- }
-
- ///
- /// 检查是否临界过载(负载超过95%)
- ///
- public static bool IsCriticalOverload(Pawn pawn)
- {
- float loadPercent = GetPsychicLoadPercent(pawn);
- return loadPercent > 0.95f;
- }
-
- ///
- /// 获取系统状态描述
- ///
- public static string GetSystemStatus(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetSystemStatus() ?? "无术法系统";
- }
-
- ///
- /// 获取总科研点(所有虫群单位)
- ///
- public static float GetTotalPsychicResearchPoints()
- {
- float total = 0f;
- foreach (var pawn in GetAllSpellHolders())
- {
- total += GetPsychicResearchPoints(pawn);
- }
- return total;
- }
-
- ///
- /// 获取平均术法等级(所有虫群单位)
- ///
- public static float GetAverageSpellLevel()
- {
- var holders = GetAllSpellHolders().ToList();
- if (holders.Count == 0)
- return 0f;
-
- float total = 0f;
- foreach (var pawn in holders)
- {
- total += GetSpellLevel(pawn);
- }
- return total / holders.Count;
- }
- #endregion
-
- #region 批量操作
- ///
- /// 为所有虫群单位增加科研点
- ///
- public static void AddPsychicResearchToAllSwarmPawns(float amount, string reason = "")
- {
- // 获取所有虫群派系的单位
- var swarmPawns = GetAllSwarmPawns();
- AddPsychicResearchPointsToAll(swarmPawns, amount, reason);
- }
-
- ///
- /// 为所有虫群单位增加术法等级
- ///
- public static void IncreaseSpellLevelForAllSwarmPawns(float amount, string reason = "")
- {
- var swarmPawns = GetAllSwarmPawns();
- IncreaseSpellLevelForAll(swarmPawns, amount, reason);
- }
-
- ///
- /// 获取所有虫群派系的单位
- ///
- public static IEnumerable GetAllSwarmPawns()
- {
- // 假设虫群派系的defName是"ArachnaeSwarm_Faction"
- Faction swarmFaction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("ArachnaeSwarm_Faction"));
- if (swarmFaction == null)
- yield break;
-
- foreach (Map map in Current.Game.Maps)
- {
- foreach (Pawn pawn in map.mapPawns.AllPawns)
- {
- if (pawn.Faction == swarmFaction && HasSpellHolder(pawn))
- {
- yield return pawn;
- }
- }
- }
- }
- #endregion
-
- #region 调试和工具方法
- ///
- /// 初始化术法系统(如果尚未初始化)
- ///
- public static bool EnsureSystemInitialized(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- if (holder == null)
- return false;
-
- // 组件会在PostSpawnSetup中自动初始化
- return holder.IsSystemInitialized;
- }
-
- ///
- /// 重置术法系统
- ///
- public static bool ResetSpellSystem(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- if (holder == null)
- return false;
-
- holder.ResetSystem();
- return true;
- }
-
- ///
- /// 获取调试信息
- ///
- public static string GetDebugInfo(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.GetDebugInfo() ?? "无术法组件";
- }
-
- ///
- /// 显示术法系统状态消息
- ///
- public static void ShowStatusMessage(Pawn pawn)
- {
- if (!IsSpellSystemAvailable(pawn))
- {
- Messages.Message("ARA_SwarmSpell_SystemNotAvailable".Translate(pawn.LabelShortCap), MessageTypeDefOf.NeutralEvent);
- return;
- }
-
- string message = GetSystemStatus(pawn);
- Messages.Message(message, pawn, MessageTypeDefOf.NeutralEvent);
- }
- #endregion
-
- #region 兼容性方法(保持与旧代码的兼容性)
- ///
- /// 检查Pawn是否是术法持有者
- ///
- public static bool IsSpellHolder(Pawn pawn)
- {
- return HasSpellHolder(pawn);
- }
-
- ///
- /// 获取灵能科研点百分比
- ///
- public static float GetPsychicResearchPercent(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.PsychicResearchPercent ?? 0f;
- }
-
- ///
- /// 获取灵能负载容量百分比
- ///
- public static float GetPsychicLoadCapacityPercent(Pawn pawn)
- {
- var holder = GetSpellHolder(pawn);
- return holder?.PsychicLoadPercent ?? 0f;
- }
- #endregion
- }
-}