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 - } -}