diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 971eefa..2432d37 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/AbilityDefs/ARA_Abilities.xml b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml index 78fe037..a20a06b 100644 --- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml +++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml @@ -499,7 +499,7 @@ ARA_HiveMindDrone -
  • ArachnaeQueen_Race_Titan
  • +
  • ArachnaeQueen_Race
  • @@ -1678,6 +1678,4 @@ - - \ No newline at end of file diff --git a/1.6/1.6/Defs/AbilityDefs/ARA_Psy_Abilities.xml b/1.6/1.6/Defs/AbilityDefs/ARA_Psy_Abilities.xml new file mode 100644 index 0000000..37a25f8 --- /dev/null +++ b/1.6/1.6/Defs/AbilityDefs/ARA_Psy_Abilities.xml @@ -0,0 +1,63 @@ + + + + ARA_Neurotyrant_PsychicBrainburn + + 以强大的纯净灵能冲击目标,烧毁目标的中枢神经系统——这会直接杀死目标。 + + + ArachnaeSwarm/UI/Abilities/ARA_PsychicBrainburn + 60 + false + 300 + false + true + true + true + 0.5 + Mote_HoraxSmallSpellWarmup + HoraxianAbilityCasting + AnomalyAbilityWarmup + true + + Verb_CastAbility + 1 + 25 + + true + false + false + + + +
  • + + + 2.5 + 7.5 + + true + Psychic Load Cost + true + + + + + + true + 99999 + ARA_SwarmSpell_Overdrive + true +
  • +
  • + false + + Skip_Entry + + + false +
  • +
    +
    +
    diff --git a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml index 56b63ca..290e51a 100644 --- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml +++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml @@ -200,4 +200,24 @@ + + + ARA_SwarmSpell_Overdrive + + 阿拉克涅灵吸种的神经束在连续施术后会进入超负荷状态——这种状态会持续压迫灵吸种神经系统,直到完全烧毁。\n\n这种状况是无法自行缓解的,灵吸种只能将这种高额负载导流到其他个体的身上。对于那些拥有启灵神经的个体来说,这种导流不会致命,但是那些没有启灵神经的个体可就不一定了。 + HediffWithComps + false + (0.6, 0.6, 0.6) + false + + + +
  • + HediffComp_DisappearsAndKills_Shambler + 3600~3600 + true +
  • +
  • + + \ No newline at end of file diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml index 7c36ce3..282e5ed 100644 --- a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml +++ b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml @@ -43,9 +43,9 @@ - ArachnaeQueen_Race_Titan + ARA_ArachnaeQueen - ArachnaeQueen_Race_Titan + ArachnaeQueen_Race PlayerColony 0 @@ -65,14 +65,14 @@ - ArachnaeQueen_Race_TitanSettings + ARA_ArachnaeQueenSettings
  • -
  • ArachnaeQueen_Race_Titan
  • +
  • ARA_ArachnaeQueen
  • 100.0 @@ -87,7 +87,7 @@
  • -
  • ArachnaeQueen_Race_Titan
  • +
  • ARA_ArachnaeQueen
  • ArachnaeNode_Race_ShieldHead
  • ArachnaeNode_Race_WeaponSmith
  • ArachnaeNode_Race_Fighter
  • @@ -110,7 +110,7 @@
  • -
  • ArachnaeQueen_Race_Titan
  • +
  • ARA_ArachnaeQueen
  • ArachnaeNode_Race_ShieldHead
  • ArachnaeNode_Race_WeaponSmith
  • ArachnaeNode_Race_Fighter
  • @@ -128,7 +128,7 @@
  • -
  • ArachnaeQueen_Race_Titan
  • +
  • ARA_ArachnaeQueen
  • ArachnaeNode_Race_ShieldHead
  • ArachnaeNode_Race_WeaponSmith
  • ArachnaeNode_Race_Fighter
  • diff --git a/1.6/1.6/Defs/Scenarios/ARA_Scenarios.xml b/1.6/1.6/Defs/Scenarios/ARA_Scenarios.xml index 53f285a..222c634 100644 --- a/1.6/1.6/Defs/Scenarios/ARA_Scenarios.xml +++ b/1.6/1.6/Defs/Scenarios/ARA_Scenarios.xml @@ -22,7 +22,7 @@
  • True - ArachnaeQueen_Race_Neurotyrant + ARA_ArachnaeQueen
  • diff --git a/1.6/1.6/Defs/Stats/ARA_Stats.xml b/1.6/1.6/Defs/Stats/ARA_Stats.xml index b1333a7..755f5e7 100644 --- a/1.6/1.6/Defs/Stats/ARA_Stats.xml +++ b/1.6/1.6/Defs/Stats/ARA_Stats.xml @@ -100,4 +100,16 @@ 2201 false + + ARA_SwarmSpell_Cooldown_Delay + + 当阿拉克涅灵吸种使用虫群灵能能力时,产生的灵能负荷会在此时间后开始逐渐下降,任何施术都会重置冷却时间。 + ARA_GestaltNetwork + 0 + Integer + 0 + 0 + 2201 + false + \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml index 8bf24cb..08aff34 100644 --- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml +++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml @@ -699,7 +699,7 @@
    - ArachnaeQueen_Race_Titan + ArachnaeQueen_Race 阿拉克涅泰坦种是女皇种亚种之一,归属于阿拉克涅的泰坦触须。她们指挥着阿拉克涅虫群中最坚韧、最具有适应力的主力集团族群,承担在战场上维持战线的任务。\n\n泰坦种女皇除了可以提供泰坦触须的独特科技外,自身也有强大的甲壳作为防御层,还可以通过践踏和高额的近战伤害攻击靠近的敌人。 @@ -814,7 +814,7 @@ ArachnaeQueen_Race_Neurotyrant - 阿拉克涅灵吸种是女皇种亚种之一,归属于阿拉克涅的灵能触须。她们负责维持虫族蜂巢灵能网路的通讯,并作为中继节点链接各战区女皇种和虫巢舰队。\n\n但是灵吸种可不是脆弱的“文官”,她们强大的灵能使得她们可以通过超自然力量主宰当地战局,随着她们不断吞噬本地物种,其灵能能力还能得到不断的进化。 + 阿拉克涅灵吸种是女皇种亚种之一,归属于阿拉克涅的灵能触须。她们负责维持虫族蜂巢灵能网路的通讯,并作为中继节点链接各战区女皇种和虫巢舰队。\n\n灵吸种是天生的灵能大师,她们强大的灵能使得她们可以通过超自然力量主宰当地战局,随着她们不断吞噬本地物种,其灵能能力还能得到适应性进化。 @@ -873,6 +873,7 @@ 9999 0 + 60 @@ -884,14 +885,6 @@ -
  • - - -
  • Crush
  • - - 10 - 2.1 -
  • @@ -903,6 +896,7 @@ +
  • Drafted diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_Things_Items.xml b/1.6/1.6/Defs/Thing_Misc/ARA_Things_Items.xml index 1f42b92..bee7425 100644 --- a/1.6/1.6/Defs/Thing_Misc/ARA_Things_Items.xml +++ b/1.6/1.6/Defs/Thing_Misc/ARA_Things_Items.xml @@ -68,7 +68,7 @@
  • ArachnaeNode_Race_Skyraider
  • ArachnaeNode_Race_NeuroSwarm
  • ArachnaeNode_Race_Praetorian
  • -
  • ArachnaeQueen_Race_Titan
  • +
  • ArachnaeQueen_Race
  • diff --git a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml index 929656a..c69e92b 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml @@ -76,7 +76,7 @@ -
  • ArachnaeQueen_Race_Titan
  • +
  • ARA_ArachnaeQueen
  • true @@ -95,7 +95,7 @@ 用于孵化阿拉克涅女皇种的超巨型卵囊,表皮坚硬地堪比堡垒,内部蕴含的遗传物质和营养足以孵化出这个星球闻所未闻的庞然大物。 - ArachnaeQueen_Race_Titan + ArachnaeQueen_Race (0.9, 0.9 ,0.5) @@ -124,12 +124,12 @@
  • - ArachnaeQueen_Race_Titan + ARA_ArachnaeQueen 180000
  • true diff --git a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml index 6e831ce..03202e2 100644 --- a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml +++ b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml @@ -1445,6 +1445,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -1591,6 +1600,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • @@ -1722,6 +1741,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -1817,6 +1845,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • @@ -2033,6 +2071,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -2128,6 +2175,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • @@ -2337,6 +2394,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -2483,6 +2549,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • @@ -2611,6 +2687,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -2757,6 +2842,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • @@ -2885,6 +2980,15 @@
  • + +
  • + HighPriority + +
  • + LordDuty +
  • + +
  • @@ -3060,6 +3164,16 @@ SatisfyBasicNeeds
  • + +
  • + MediumPriority + +
  • + LordDuty +
  • + + +
  • diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Alerts_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Alerts_Keys.xml deleted file mode 100644 index cc265e5..0000000 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Alerts_Keys.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - 未连接的虫群工蜂 - 地图上存在未连接到阿拉克涅女皇种的虫群工蜂。这些工蜂将在一段时间后死亡。请尽快将它们与阿拉克涅女皇种连接。 - - \ No newline at end of file diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml index e306ce4..565ee2e 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_Building_Ootheca.xml @@ -260,4 +260,10 @@ 多选 ({0}个) 还有 {0} 个建筑... 空闲 + + 手动 + 品质 + 平衡 + 速度 + diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_QueuedIncubator.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_QueuedIncubator.xml index aa19c81..3f139d4 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_QueuedIncubator.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_QueuedIncubator.xml @@ -60,6 +60,7 @@ 添加订单 ({0}/{1}) 选择要孵化的单位类型(可多次点击) 选择要生产的物品(可多次点击) + 无正在进行的订单 呼叫幼虫 呼叫一只幼虫来激活下一个订单(还有{0}个等待中) 幼虫工作中 diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml index 609833b..457b62d 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/GizmoLabels.xml @@ -13,4 +13,47 @@ 警告:蜂巢网络正在超载,这将会直接影响女皇种的心情,并有可能导致整个网络的传导性崩溃! 蜂巢网络超载已结束 {1} 已经断开与 {0} 的链接! + + + 虫群术法 (Lv.{0}) + {0}/{1} + {0:F1}/{1:F1} + Spell + + + 虫群研究点 + 储存: {0} / {1} + 虫群研究点label + 虫群研究点text + + 灵能负荷 + 负荷量: {0:F1} / {1:F1} + 术法等级 + 目前的等级: {0} + 灵能负荷最大值: 10 × {0} (术法等级) + 警告: 高灵能负荷! + 警告: 灵能负荷逼近极限! + 灵能负荷label + 灵能负荷text + + 虫群术法label + 虫群术法text + 将鼠标放在指示条以进一步查看详细信息 + + + {0} 的虫群术法系统不可用 + + + [超载] 虫群术法系统 + {0:F1}/{1:F1} (+{2}) + 灵能负载 [超载] + 警告: 灵能负载超过容量! + 警告: 单位处于超载状态,冷却系统已锁定! + + + {0:F1}s + 冷却系统 + 剩余时间: {0:F1}秒 + 冷却结束后,每60ticks减少1点负载 + 冷却结束后将自动减少负载 \ No newline at end of file diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index e0bcf92..37afca6 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 2886291..2af5f92 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -1,30 +1,38 @@ { "Version": 1, - "WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", + "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_swarmspellholder\\gizmo_swarmspellstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_swarmspellholder\\gizmo_swarmspellstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_flight\\pawn_flighttrackerpatches.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_flight\\pawn_flighttrackerpatches.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|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\pawn_comps\\ara_uniquepawn\\compuniquepawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\compuniquepawn.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_psychicloadcost\\compabilityeffect_psychicloadcost.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloadcost\\compabilityeffect_psychicloadcost.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\pawn_comps\\ara_uniquepawn\\uniquepawnmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\uniquepawnmanager.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|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\pawn_comps\\ara_uniquepawn\\compproperties_uniquepawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\compproperties_uniquepawn.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_psychicloadcost\\compproperties_abilitypsychicloadcost.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloadcost\\compproperties_abilitypsychicloadcost.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\pawn_comps\\ara_flight\\compproperties_pawnflight.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_flight\\compproperties_pawnflight.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\\psychicbrainburn\\compabilityeffect_psychicbrainburn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\psychicbrainburn\\compabilityeffect_psychicbrainburn.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\\swarmspellutility.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_swarmspellholder\\swarmspellutility.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_automechcarrier\\compautomechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_automechcarrier\\compautomechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" } ], "DocumentGroupContainers": [ @@ -37,82 +45,112 @@ "SelectedChildIndex": 1, "Children": [ { - "$type": "Bookmark", - "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" + "$type": "Document", + "DocumentIndex": 4, + "Title": "CompProperties_AbilityPsychicLoadCost.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", + "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", + "RelativeToolTip": "Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", + "ViewState": "AgIAAAsAAAAAAAAAAADwvyUAAAAAAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-30T08:22:38.845Z", + "EditorCaption": "" }, { "$type": "Document", "DocumentIndex": 0, - "Title": "Building_Ootheca.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs", - "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs", - "RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs", - "ViewState": "AgIAAAAAAAAAAAAAAADwvw8AAAA1AAAAAAAAAA==", + "Title": "Gizmo_SwarmSpellStatus.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", + "RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", + "RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", + "ViewState": "AgIAAGcAAAAAAAAAAAAMwIIAAAAMAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-29T14:12:44.657Z", + "WhenOpened": "2026-01-30T08:20:07.463Z", "EditorCaption": "" }, { "$type": "Document", "DocumentIndex": 2, - "Title": "CompUniquePawn.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", - "RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", - "RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAACIAAAAIAAAAAAAAAA==", + "Title": "CompAbilityEffect_PsychicLoadCost.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", + "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", + "RelativeToolTip": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", + "ViewState": "AgIAAEgAAAAAAAAAAAApwFkAAABWAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-28T09:15:14.392Z" + "WhenOpened": "2026-01-30T08:16:09.317Z", + "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 4, - "Title": "CompProperties_UniquePawn.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompProperties_UniquePawn.cs", - "RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\CompProperties_UniquePawn.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompProperties_UniquePawn.cs", - "RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\CompProperties_UniquePawn.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAAAAAAAAAAAAAA==", + "DocumentIndex": 5, + "Title": "CompAbilityEffect_PsychicBrainburn.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", + "RelativeDocumentMoniker": "Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", + "RelativeToolTip": "Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAANAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-28T09:15:09.995Z" + "WhenOpened": "2026-01-30T08:11:40.772Z", + "EditorCaption": "" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" }, { "$type": "Document", "DocumentIndex": 1, - "Title": "Pawn_FlightTrackerPatches.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs", - "RelativeDocumentMoniker": "Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs", - "RelativeToolTip": "Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs", - "ViewState": "AgIAADgAAAAAAAAAAIA1wE4AAAAAAAAAAAAAAA==", + "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": "AgIAAEgAAAAAAAAAAAA7wF4AAAA7AAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-28T08:32:19.011Z", + "WhenOpened": "2026-01-30T07:47:08.641Z", "EditorCaption": "" }, { "$type": "Document", "DocumentIndex": 3, - "Title": "UniquePawnManager.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", - "RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", - "RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", - "ViewState": "AgIAAIIBAAAAAAAAAAAtwJUBAAANAAAAAAAAAA==", + "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": "AgIAAAAAAAAAAAAAAAAAAFwDAAAFAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-28T09:15:15.046Z" + "WhenOpened": "2026-01-30T07:11:59.797Z", + "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 5, - "Title": "CompProperties_PawnFlight.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs", - "RelativeDocumentMoniker": "Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs", - "RelativeToolTip": "Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAuwAgAAAAWAAAAAAAAAA==", + "DocumentIndex": 6, + "Title": "SwarmSpellUtility.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", + "RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", + "RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAAPMAAAANAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-28T08:30:19.937Z" + "WhenOpened": "2026-01-30T07:25:10.449Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 7, + "Title": "CompAutoMechCarrier.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", + "RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", + "RelativeToolTip": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", + "ViewState": "AgIAAAwAAAAAAAAAAAAtwE4AAAAVAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-01-30T07:25:22.745Z", + "EditorCaption": "" } ] } diff --git a/Source/ArachnaeSwarm/ARA_DefOf.cs b/Source/ArachnaeSwarm/ARA_DefOf.cs index 4676146..f3678ca 100644 --- a/Source/ArachnaeSwarm/ARA_DefOf.cs +++ b/Source/ArachnaeSwarm/ARA_DefOf.cs @@ -22,6 +22,7 @@ namespace ArachnaeSwarm public static HediffDef ARA_HiveMindDrone; public static HediffDef ARA_HiveMindWorker; public static HediffDef ARA_GestaltNetworkOverload; + public static HediffDef ARA_SwarmSpell_Overdrive; static ARA_HediffDefOf() { @@ -91,7 +92,8 @@ namespace ArachnaeSwarm { public static StatDef ARA_GestaltBandwidth; public static StatDef ARA_GestaltBandwidthCost; - + public static StatDef ARA_SwarmSpell_Cooldown_Delay; + static ARA_StatDefOf() { DefOfHelper.EnsureInitializedInCtor(typeof(ARA_StatDefOf)); diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs new file mode 100644 index 0000000..9c081ae --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompAbilityEffect_PsychicLoadCost.cs @@ -0,0 +1,300 @@ +using RimWorld; +using System; +using System.Linq; +using System.Text; +using UnityEngine; +using Verse; + +namespace ArachnaeSwarm +{ + /// + /// 灵能负载消耗技能效果 + /// + public class CompAbilityEffect_PsychicLoadCost : CompAbilityEffect + { + #region 属性 + public new CompProperties_AbilityPsychicLoadCost Props => (CompProperties_AbilityPsychicLoadCost)props; + + /// + /// 获取实际负载消耗(随机或固定) + /// + public float ActualLoadCost + { + get + { + if (Props.useFixedCost) + { + return Props.fixedLoadCost; + } + else + { + return Props.loadCostRange.RandomInRange; + } + } + } + #endregion + + #region 技能效果应用 + 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, $"释放技能: {parent.def.label}"); + + // 检查当前是否超载 + bool isNowOverloaded = spellHolder.IsOverloaded; + + // 如果从非超载状态变为超载状态,显示警告 + if (!wasOverloaded && isNowOverloaded) + { + Messages.Message("ARA_SwarmSpell_Overload_Warning".Translate(caster.LabelShortCap), + caster, MessageTypeDefOf.NegativeEvent); + } + + // 如果已经在超载状态时施放技能,应用惩罚 + if (wasOverloaded && Props.applyOverloadPenalty) + { + ApplyOverloadPenalty(caster, target); + } + } + #endregion + + #region 超载惩罚 + /// + /// 应用超载惩罚 + /// + private void ApplyOverloadPenalty(Pawn caster, LocalTargetInfo target) + { + try + { + // 应用超载惩罚Hediff + 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 (var 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 (var 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}"); + } + } + #endregion + + #region Gizmo 相关 + public override bool GizmoDisabled(out string reason) + { + // 总是允许施放(忽略超载检查) + 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"))); + } + + // 当前负载状态 + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_CurrentLoad".Translate().Colorize(ColoredText.TipSectionTitleColor)); + sb.AppendLine("ARA_SwarmSpell_Load_Current".Translate( + spellHolder.PsychicLoad.ToString("F1"), + spellHolder.PsychicLoadCapacity.ToString("F1"))); + + // 超载警告 + if (spellHolder.IsOverloaded) + { + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Overload_Warning_Tooltip".Translate().Colorize(Color.red)); + sb.AppendLine("ARA_SwarmSpell_Overload_Penalty_Description".Translate()); + } + else + { + // 施放后预测负载 + float predictedLoad = spellHolder.PsychicLoad + (Props.useFixedCost ? Props.fixedLoadCost : Props.loadCostRange.Average); + float predictedPercent = spellHolder.PsychicLoadCapacity > 0 ? predictedLoad / spellHolder.PsychicLoadCapacity : 0f; + + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_PredictedLoad".Translate().Colorize(ColoredText.TipSectionTitleColor)); + sb.AppendLine("ARA_SwarmSpell_PredictedLoad_Value".Translate(predictedLoad.ToString("F1"), spellHolder.PsychicLoadCapacity.ToString("F1"))); + + if (predictedPercent > 0.8f) + { + sb.AppendLine("ARA_SwarmSpell_PredictedLoad_Warning".Translate(predictedPercent.ToStringPercent()).Colorize(Color.yellow)); + } + + if (predictedPercent > 1f) + { + sb.AppendLine("ARA_SwarmSpell_PredictedLoad_Overload".Translate().Colorize(Color.red)); + } + } + + return sb.ToString().TrimEndNewlines(); + } + + public override void DrawEffectPreview(LocalTargetInfo target) + { + base.DrawEffectPreview(target); + + // 可以在预览时显示一些效果,但这不是必须的 + } + #endregion + + #region AI 行为 + 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; + + // AI 不会在超载状态下使用此技能(避免自我伤害) + if (spellHolder.IsOverloaded) + return false; + + // 检查施放后的负载预测 + float predictedLoad = spellHolder.PsychicLoad + (Props.useFixedCost ? Props.fixedLoadCost : Props.loadCostRange.Average); + float predictedPercent = spellHolder.PsychicLoadCapacity > 0 ? predictedLoad / spellHolder.PsychicLoadCapacity : 0f; + + // AI 会避免可能导致严重超载的技能 + if (predictedPercent > 0.9f) + return false; + + return base.AICanTargetNow(target); + } + #endregion + } +} diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs new file mode 100644 index 0000000..5ecb773 --- /dev/null +++ b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadCost/CompProperties_AbilityPsychicLoadCost.cs @@ -0,0 +1,37 @@ +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/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index 05c750b..de1044a 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -34,6 +34,8 @@ 4 + + @@ -358,6 +360,9 @@ + + + diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs index 3af71b2..ac1b535 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Building_Ootheca.cs @@ -55,10 +55,10 @@ namespace ArachnaeSwarm public void SetFluxMode(FluxMode mode) => fluxMode = mode; public string GetModeName() => fluxMode switch { - FluxMode.Manual => "手动", - FluxMode.Quality => "品质", - FluxMode.Balance => "平衡", - FluxMode.Speed => "速度", + FluxMode.Manual => "ARA_Gizmo_Manual".Translate(), + FluxMode.Quality => "ARA_Gizmo_Quality".Translate(), + FluxMode.Balance => "ARA_Gizmo_Balance".Translate(), + FluxMode.Speed => "ARA_Gizmo_Speed".Translate(), _ => "?" }; @@ -110,7 +110,7 @@ namespace ArachnaeSwarm label = incubatingPawnKind.LabelCap, progress = AdjustedProgressPercent, qualityProgress = QualityPercent, - estimatedQuality = QualityPercent > 0.8f ? "优秀" : QualityPercent > 0.5f ? "良好" : "普通", + estimatedQuality = QualityPercent > 0.8f ? "ARA_Quality_Excellent".Translate() : QualityPercent > 0.5f ? "ARA_Quality_Good".Translate() : "ARA_Quality_Normal".Translate(), remainingTime = GetRemainingDays() > 0 ? GetRemainingDays().ToString("F1") + " " + "ARA_Days".Translate() : "", status = OrderStatus.Incubating }); @@ -176,18 +176,18 @@ namespace ArachnaeSwarm public string GetSpeedFactorsDescription() { var builder = new StringBuilder(); - builder.AppendLine("速度因子"); + builder.AppendLine("ARA_Gizmo_SpeedFactors".Translate()); builder.AppendLine(); - builder.AppendLine("总速度倍率: " + SpeedMultiplier.ToStringPercent()); + builder.AppendLine("ARA_Gizmo_TotalSpeedMultiplier".Translate(SpeedMultiplier)); return builder.ToString().TrimEndNewlines(); } public string GetQualityFactorsDescription() { var builder = new StringBuilder(); - builder.AppendLine("质量因子"); + builder.AppendLine("ARA_Gizmo_QualityFactors".Translate()); builder.AppendLine(); - builder.AppendLine("总质量倍率: " + QualityMultiplier.ToStringPercent()); + builder.AppendLine("ARA_Gizmo_TotalQualityMultiplier".Translate(QualityMultiplier)); return builder.ToString().TrimEndNewlines(); } @@ -561,67 +561,68 @@ namespace ArachnaeSwarm } public override IEnumerable GetGizmos() { + // 首先添加中子通量Gizmo(最重要的控制) + if (Faction == Faction.OfPlayer) + { + yield return new Gizmo_NeutronFlux(this); + } + // 然后是基础Gizmo,但过滤一些不需要的 foreach (var gizmo in base.GetGizmos()) { if (gizmo is Command_Action cmd && cmd.defaultLabel != null) { string label = cmd.defaultLabel.ToString(); - if (label.Contains("拆除") || label.Contains("Deconstruct") || label.Contains("半径") || label.Contains("Radius")) + // 过滤掉不相关的Gizmo + if (label.Contains("拆除") || label.Contains("Deconstruct") || + label.Contains("半径") || label.Contains("Radius") || + label.Contains("卸载") || label.Contains("Uninstall")) + { continue; + } } - - // 强制将基础组件(如 Refuelable)甚至默认排序为 -100 的东西移到后面 + // 调整其他基础Gizmo的Order,让它们显示在后面 if (gizmo.Order >= -100f && gizmo.Order <= 0f) { - gizmo.Order = -90f; + gizmo.Order = -50f; } - yield return gizmo; } - - // 首先获取选中的同类建筑 - var selectedOothecas = GetSelectedOothecas(); - bool isMultiSelect = selectedOothecas.Count > 1; - + // 然后是自定义命令Gizmo if (Faction == Faction.OfPlayer) { + var selectedOothecas = GetSelectedOothecas(); + bool isMultiSelect = selectedOothecas.Count > 1; var config = IncubatorData?.SelectedConfig; - - // 添加订单按钮(多选时合并) + // 订单按钮 if (!isIncubating && assignedLarva == null) { // 多选时,只在第一个建筑上显示 if (!isMultiSelect || (isMultiSelect && selectedOothecas.First() == this)) { - // 计算多选时的计数 int selectedCount = selectedOothecas.Count(o => !o.isIncubating && o.assignedLarva == null); int selectedWithConfig = selectedOothecas.Count(o => !o.isIncubating && o.assignedLarva == null && o.IncubatorData?.SelectedConfig != null); - string label = isMultiSelect ? $"ARA_Gizmo_AddOrder_Multi".Translate(selectedWithConfig, selectedCount) : "ARA_Gizmo_AddOrder".Translate(config != null ? 1 : 0, 1); - string desc = isMultiSelect ? "ARA_Gizmo_AddOrderDesc_Multi".Translate(selectedCount) : "ARA_Gizmo_AddOrderDesc_Pawn".Translate(); - yield return new Command_Action { defaultLabel = label, defaultDesc = desc, icon = ContentFinder.Get("ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon", false), action = () => ShowMultiSelectOrderMenu(selectedOothecas), - Order = 100f + Order = 200f // 高Order,显示在后面 }; } } - // 呼叫幼虫按钮逻辑(多选时同样处理) + // 呼叫幼虫按钮 if (!isIncubating && config != null && config.IsResearchComplete) { if (assignedLarva == null) { - // 多选时只在第一个建筑上显示,但会为所有符合条件的建筑呼叫幼虫 if (!isMultiSelect || (isMultiSelect && selectedOothecas.First() == this)) { yield return new Command_Action @@ -630,7 +631,7 @@ namespace ArachnaeSwarm defaultDesc = BuildCallLarvaDescription(config), icon = ContentFinder.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false), action = () => CallLarvaForMultiSelect(selectedOothecas), - Order = 100f + Order = 210f }; } } @@ -640,7 +641,6 @@ namespace ArachnaeSwarm string statusText = larvaOperateTicksRemaining > 0 ? "ARA_Gizmo_LarvaActivating".Translate() : "ARA_Gizmo_LarvaOnTheWay".Translate(); - if (!isMultiSelect || (isMultiSelect && selectedOothecas.First() == this)) { yield return new Command_Action @@ -649,7 +649,7 @@ namespace ArachnaeSwarm defaultDesc = "ARA_Gizmo_LarvaWorkingDesc".Translate(0), icon = ContentFinder.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false), Disabled = true, - Order = 100f + Order = 210f }; } } @@ -662,7 +662,7 @@ namespace ArachnaeSwarm defaultLabel = "ARA_OothecaIncubator.CancelIncubation".Translate(), icon = ContentFinder.Get("UI/Commands/Cancel", false), action = () => CancelIncubationForMultiSelect(selectedOothecas), - Order = 100f + Order = 220f }; } } diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_QueuedIncubationProgress.cs b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_QueuedIncubationProgress.cs index 852ed3a..89a7b8c 100644 --- a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_QueuedIncubationProgress.cs +++ b/Source/ArachnaeSwarm/Buildings/Building_Ootheca/Gizmo_QueuedIncubationProgress.cs @@ -99,7 +99,7 @@ namespace ArachnaeSwarm else if (hasTarget) { GUI.color = new Color(0.5f, 1f, 0.5f); - if (Widgets.ButtonText(titleRect, "呼叫幼虫")) + if (Widgets.ButtonText(titleRect, "ARA_Gizmo_CallLarva".Translate())) { callLarva?.Invoke(); } @@ -128,7 +128,7 @@ namespace ArachnaeSwarm Rect emptyRect = new Rect(gizmoRect.x + Padding, curY, gizmoRect.width - Padding * 2, BarHeight); Text.Font = GameFont.Tiny; GUI.color = Color.gray; - Widgets.Label(emptyRect, "无正在进行的订单"); + Widgets.Label(emptyRect, "ARA_Gizmo_NoavliableOrder".Translate()); GUI.color = Color.white; } diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_AutoMechCarrier/CompAutoMechCarrier.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_AutoMechCarrier/CompAutoMechCarrier.cs index 0081688..adf2f2d 100644 --- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_AutoMechCarrier/CompAutoMechCarrier.cs +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_AutoMechCarrier/CompAutoMechCarrier.cs @@ -72,7 +72,10 @@ namespace ArachnaeSwarm private IntVec3? customFollowPosition = null; private Map customFollowPositionMap = null; private object customPositionLock = new object(); - + private bool isProductionPaused = false; + private Lord cachedLord = null; + private bool cachedIsInLordJob = false; + /// /// 获取或设置自定义跟随位置 /// @@ -103,7 +106,55 @@ namespace ArachnaeSwarm } } } - + + // 主要检测逻辑 + private void CheckProductionPause() + { + if (parent is Pawn pawnParent) + { + // 获取Lord(缓存以提高性能) + if (Find.TickManager.TicksGame % 60 == 0) + { + cachedLord = pawnParent.GetLord(); + } + + // 检查是否有LordJob + bool hasLordJob = cachedLord != null && cachedLord.LordJob != null; + + // 如果是LordJob且与上次状态不同,更新 + if (hasLordJob != cachedIsInLordJob) + { + cachedIsInLordJob = hasLordJob; + UpdateProductionPauseState(hasLordJob); + } + } + } + + /// + /// 更新生产暂停状态 + /// + private void UpdateProductionPauseState(bool shouldPause) + { + bool oldState = isProductionPaused; + + if (shouldPause) + { + // 进入LordJob,暂停生产 + if (!isProductionPaused) + { + isProductionPaused = true; + } + } + else + { + // 离开LordJob,恢复生产 + if (isProductionPaused) + { + isProductionPaused = false; + } + } + } + /// /// 检查自定义位置是否有效 /// @@ -675,7 +726,7 @@ namespace ArachnaeSwarm { return; } - + var productionQueue = GetProductionQueue(); if (productionQueue == null || productionQueue.Count == 0) { @@ -698,6 +749,12 @@ namespace ArachnaeSwarm return; } + CheckProductionPause(); + if (isProductionPaused) + { + return; + } + if (CooldownTicksRemaining > 0) return; foreach (var entry in productionQueue) diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs new file mode 100644 index 0000000..015d38c --- /dev/null +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Comp_SwarmSpellHolder.cs @@ -0,0 +1,877 @@ +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 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 = Mathf.Max(0f, value); + + // 更新负载容量 + 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; + #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); + + if (Scribe.mode == LoadSaveMode.LoadingVars) + { + // 加载后重新计算负载容量以确保一致性 + if (psychicLoadCapacity <= 0) + { + psychicLoadCapacity = spellLevel * PSYCHIC_LOAD_PER_LEVEL; + } + + // 重新检查超载状态 + CheckOverloadStatus(); + } + } + #endregion + + #region 初始化方法 + /// + /// 初始化术法系统 + /// + private void InitializeSystem() + { + if (systemInitialized) + return; + + // 设置初始值 + spellLevel = SPELL_LEVEL_MULTIPLIER; + 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 spellLevel; + } + + /// + /// 设置术法等级 + /// + 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 new file mode 100644 index 0000000..fdb04c7 --- /dev/null +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/Gizmo_SwarmSpellStatus.cs @@ -0,0 +1,272 @@ +using RimWorld; +using UnityEngine; +using Verse; +using System.Text; + +namespace ArachnaeSwarm +{ + [StaticConstructorOnStartup] + public class Gizmo_SwarmSpellStatus : Gizmo + { + private Comp_SwarmSpellHolder spellHolder; + + // 材质定义 + private static readonly Texture2D FullResearchBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.4f, 0.9f)); // 绿色 - 科研点 + private static readonly Texture2D EmptyResearchBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.3f, 0.2f, 0.8f)); // 深绿 - 科研点背景 + private static readonly Texture2D FullLoadBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.8f, 0.2f, 0.4f, 0.9f)); // 红色 - 正常负载 + private static readonly Texture2D OverloadBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 0.2f, 0.2f, 0.9f)); // 亮红色 - 超载 + private static readonly Texture2D EmptyLoadBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.3f, 0.1f, 0.2f, 0.8f)); // 深红 - 负载背景 + private static readonly Texture2D WarningTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.7f, 0.2f, 0.9f)); // 黄色 - 警告 + private static readonly Texture2D CooldownBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.4f, 0.4f, 0.8f, 0.7f)); // 蓝色 - 冷却条 + + // 布局常量 + private const float GizmoWidth = 160f; + private const float GizmoHeight = 75f; // 增加高度以显示冷却条 + private const float Padding = 4f; + private const float TitleHeight = 18f; + private const float BarHeight = 16f; + private const float BarSpacing = 4f; + private const float InfoHeight = 14f; + + public Gizmo_SwarmSpellStatus(Comp_SwarmSpellHolder holder) + { + this.spellHolder = holder; + Order = -95f; // 在护盾Gizmo之前显示 + } + + public override float GetWidth(float maxWidth) + { + return Mathf.Min(GizmoWidth, maxWidth); + } + + 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); + + // 标题区域 + Rect titleRect = new Rect(contentRect.x, contentRect.y, contentRect.width, TitleHeight); + Text.Font = GameFont.Tiny; + Text.Anchor = TextAnchor.UpperCenter; + GUI.color = new Color(0.9f, 0.5f, 0.9f); // 紫色,虫群主题色 + + // 如果有超载,标题显示警告 + if (spellHolder.IsOverloaded) + { + GUI.color = Color.red; + Widgets.Label(titleRect, "ARA_SwarmSpell_Title".Translate(spellHolder.SpellLevel.ToString("F1"))); + } + else + { + Widgets.Label(titleRect, "ARA_SwarmSpell_Title".Translate(spellHolder.SpellLevel.ToString("F1"))); + } + + Text.Anchor = TextAnchor.UpperLeft; + GUI.color = Color.white; + + float currentY = titleRect.yMax + BarSpacing; + + // === 灵能科研点条 === + Rect researchBarRect = new Rect(contentRect.x, currentY, contentRect.width, BarHeight); + + // 绘制科研点条 + float researchPercent = spellHolder.PsychicResearchPercent; + Texture2D researchBarTex = researchPercent > 0.8f ? WarningTex : FullResearchBarTex; + Widgets.FillableBar(researchBarRect, researchPercent, researchBarTex, EmptyResearchBarTex, doBorder: true); + + // 绘制科研点文本 + Text.Font = GameFont.Small; + Text.Anchor = TextAnchor.MiddleCenter; + string researchText = $"ARA_SwarmSpell_Research".Translate(spellHolder.PsychicResearchPoints.ToString("F0"), spellHolder.MaxPsychicResearchPoints.ToString("F0")); + GUI.color = Color.white; + Widgets.Label(researchBarRect, researchText); + Text.Anchor = TextAnchor.UpperLeft; + + // 科研点悬浮提示 + string researchTooltip = GenerateResearchTooltip(); + TooltipHandler.TipRegion(researchBarRect, new TipSignal(researchTooltip, 43501)); + + currentY = researchBarRect.yMax + BarSpacing; + + // === 灵能负载条 === + Rect loadBarRect = new Rect(contentRect.x, currentY, contentRect.width, BarHeight); + + // 绘制负载条 - 超载时使用红色条,但长度限制为100% + float loadPercent = spellHolder.PsychicLoadPercentForDisplay; + Texture2D loadBarTex = spellHolder.IsOverloaded ? OverloadBarTex : (loadPercent > 0.7f ? WarningTex : FullLoadBarTex); + Widgets.FillableBar(loadBarRect, loadPercent, loadBarTex, EmptyLoadBarTex, doBorder: true); + + // 绘制负载文本 - 超载时显示额外信息 + Text.Font = GameFont.Small; + Text.Anchor = TextAnchor.MiddleCenter; + 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")); + } + GUI.color = Color.white; + Widgets.Label(loadBarRect, loadText); + Text.Anchor = TextAnchor.UpperLeft; + + // 负载悬浮提示 + string loadTooltip = GenerateLoadTooltip(); + TooltipHandler.TipRegion(loadBarRect, new TipSignal(loadTooltip, 43502)); + + // 整个Gizmo的基础工具提示 + string basicTooltip = GenerateBasicTooltip(); + TooltipHandler.TipRegion(rect, new TipSignal(basicTooltip, 43500)); + + return new GizmoResult(GizmoState.Clear); + } + + /// + /// 生成灵能科研点的详细悬浮提示 + /// + 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_Capacity_Title".Translate().Colorize(ColoredText.TipSectionTitleColor)); + + float remainingCapacity = spellHolder.GetRemainingResearchCapacity(); + + // 作用说明 + 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() + { + 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 (spellHolder.IsOverloaded) + { + 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("ARA_SwarmSpell_Cooldown_Behavior".Translate()); + } + else if (!spellHolder.IsOverloaded) + { + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Load_Recovery".Translate().Colorize(Color.green)); + } + + // 术法等级影响 + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Level_Title".Translate().Colorize(ColoredText.TipSectionTitleColor)); + sb.AppendLine("ARA_SwarmSpell_Level_Current".Translate(spellHolder.SpellLevel.ToString("F1"))); + sb.AppendLine("ARA_SwarmSpell_Load_CapacityFormula".Translate(spellHolder.SpellLevel.ToString("F1"))); + + // 作用说明 + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Load_Description".Translate().Colorize(ColoredText.TipSectionTitleColor)); + sb.AppendLine("ARA_SwarmSpell_Load_DescriptionText".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()); + + // 超载警告 + if (spellHolder.IsOverloaded) + { + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Gizmo_OverloadWarning".Translate()); + } + + sb.AppendLine(); + sb.AppendLine("ARA_SwarmSpell_Gizmo_Hint".Translate()); + + if (DebugSettings.godMode) + { + sb.AppendLine(); + sb.AppendLine("Debug".Translate().Colorize(Color.gray)); + sb.AppendLine($"超载状态: {spellHolder.IsOverloaded}"); + sb.AppendLine($"冷却状态: {spellHolder.IsOnCooldown}"); + sb.AppendLine($"冷却剩余: {spellHolder.CooldownSecondsRemaining:F1}秒"); + sb.AppendLine($"系统初始化: {spellHolder.IsSystemInitialized}"); + sb.AppendLine($"单位: {spellHolder.parent.LabelCap}"); + } + + return sb.ToString(); + } + + /// + /// 检查是否应该显示此Gizmo + /// + 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 new file mode 100644 index 0000000..d01faf9 --- /dev/null +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_SwarmSpellHolder/SwarmSpellUtility.cs @@ -0,0 +1,439 @@ +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 + } +}