diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index e45e816..fd734bf 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 241fdd1..ca0c8b3 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -312,7 +312,6 @@
ARA_Technology_6VXI
- 需要科技 节点VXI-6"酸囊" 以解锁技能
@@ -394,7 +393,6 @@
ARA_Technology_5PAV
- 需要科技 节点PAV-5"毒刺" 以解锁技能
@@ -440,7 +438,6 @@
ARA_Technology_6VXI
- 需要科技 节点VXI-6"酸囊" 以解锁技能
@@ -934,7 +931,7 @@
-
+
ARA_MimicNematode_Needle_Fire
@@ -975,7 +972,6 @@
-->
ARA_Technology_2MED
- 需要科技 节点MED-2"拟线寄生" 以解锁技能
@@ -993,6 +989,86 @@
40
+
+ ARA_FireSpew
+
+ 爆燃种经过短暂蓄力后,向前大范围地喷出火焰。这种火焰喷射距离不是太长,但是可以形成一道致密的火墙。
+ ArachnaeSwarm/UI/Abilities/ARA_FireSpew
+ 5000
+ true
+ true
+ true
+ FireSpew_Warmup
+ 3
+ true
+
+ Verb_CastAbility
+ 10
+ 1
+ FireSpew_Resolve
+
+ true
+
+
+
+
+ 饮食
+ true
+ Food
+ 0.25
+ 营养值不足,需要进食
+
+
+ 10
+ 35
+ Filth_FlammableBile
+ Fire_Spew
+ true
+
+
+
+
+ ARA_Dissolver_Touch
+
+ 在极近的范围内向目标泼洒溶脂强酸,目标的器官会快速分解,变成大量的虫蜜。因为准头很差,无法用于战场上,只能对不反抗的目标使用。
+ ArachnaeSwarm/UI/Abilities/ARA_Fighter_Invisibility_jump
+ 1000
+ 3
+ true
+ false
+ false
+ true
+ true
+ AcidSpray_Warmup
+ CastAbilityOnThingMelee
+
+ Verb_CastAbilityTouch
+ false
+ false
+ 0.5
+ -1
+ false
+ AcidSpray_Resolve
+
+ true
+ true
+
+
+
+
+ 饮食
+ true
+ Food
+ 0.1
+ 营养值不足,需要进食
+
+
+ CompAbilityEffect_GiveHediff
+ ARA_Dissolver_Touch_Damage
+ true
+
+
+
@@ -1066,46 +1142,6 @@
-
-
- ARA_FireSpew
-
- 爆燃种经过短暂蓄力后,向前大范围地喷出火焰。这种火焰喷射距离不是太长,但是可以形成一道致密的火墙。
- ArachnaeSwarm/UI/Abilities/ARA_FireSpew
- 5000
- true
- true
- true
- FireSpew_Warmup
- 3
- true
-
- Verb_CastAbility
- 10
- 1
- FireSpew_Resolve
-
- true
-
-
-
-
- 饮食
- true
- Food
- 0.25
- 营养值不足,需要进食
-
-
- 10
- 35
- Filth_FlammableBile
- Fire_Spew
- true
-
-
-
-
ARA_Genestealer_ExtractGene
diff --git a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
index b7b01e3..68eb296 100644
--- a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
+++ b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
@@ -55,12 +55,14 @@
ARA_Myrmecocystus_Production_Medicine
ARA_Myrmecocystus_Production_Fuel
+ ARA_Myrmecocystus_Production_Dissolver
ARA_Myrmecocystus_Production_Medicine
ARA_Myrmecocystus_Production_Fuel
+ ARA_Myrmecocystus_Production_Dissolver
@@ -118,7 +120,6 @@
ARA_Technology_1MED
- 需要科技 节点MED-1"疗愈种" 以解锁进化
@@ -172,7 +173,7 @@
-
+
@@ -470,7 +564,6 @@
ARA_Technology_4CLO
- 需要科技 节点CLO-4"追猎种" 以解锁进化
@@ -555,7 +648,6 @@
ARA_Technology_5STL
- 需要科技 节点STL-5"基因窃取" 以解锁进化
@@ -692,7 +784,6 @@
ARA_Technology_1BAC
- 需要科技 节点BAC-1"育菌种" 以解锁进化
@@ -714,7 +805,7 @@
-
+
+
+ false
+
+ ARA_InsectJelly
+
+ 30
+
+
+ 0.1
+
+ 0.1
+ 0
+
+
+ false
+
+ true
+
+ true
+
+ 20
+
+
+ false
+
+ false
+
+ true
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Incubator_Reward.xml b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Incubator_Reward.xml
index c8af12d..fe87e05 100644
--- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Incubator_Reward.xml
+++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Incubator_Reward.xml
@@ -235,7 +235,6 @@
-
ARA_Incubator_6_Flaw_Hediffs
@@ -250,7 +249,6 @@
-
ARA_Incubator_7_Flaw_Hediffs
@@ -267,7 +265,6 @@
-
ARA_Incubator_8_Flaw_Hediffs
@@ -305,7 +302,6 @@
-
ARA_Incubator_Elite_AdaptiveArmor
@@ -327,7 +323,6 @@
-
ARA_Incubator_Elite_BerserkGlands
@@ -346,7 +341,6 @@
-
ARA_Incubator_Elite_PsychicResonance
diff --git a/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects.xml b/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects.xml
index 82e75bb..7cd00b8 100644
--- a/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects.xml
+++ b/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects.xml
@@ -31,7 +31,7 @@
ARA_Base_Technology
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n解锁虫群的基础科技,允许孵化基本的辅虫和武装器官。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n解锁虫群的基础科技,允许孵化基本的辅虫和武装器官。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
100
0.00
3.20
@@ -39,7 +39,7 @@
ARA_Technology_1WMT
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种和工艺种进化到下一个阶段。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种和工艺种进化到下一个阶段。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
3000
4.50
3.20
@@ -56,7 +56,7 @@
ARA_Technology_2WMT
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种和工艺种进化到下一个阶段。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种和工艺种进化到下一个阶段。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
7000
9.00
3.20
@@ -169,7 +169,7 @@
ARA_Technology_1KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——战士种。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——战士种。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
150
3.00
4.80
@@ -180,7 +180,7 @@
ARA_Technology_4KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——原虫种,一种可以寄生在别的种族身上以控制它们的特殊督虫。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——原虫种,一种可以寄生在别的种族身上以控制它们的特殊督虫。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
200
3.00
4.30
@@ -191,7 +191,7 @@
ARA_Technology_2KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——空天种,敏捷而致命的精锐虫族,拥有以飞行姿态穿梭于战场的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——空天种,敏捷而致命的精锐虫族,拥有以飞行姿态穿梭于战场的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1600
5.50
4.30
@@ -205,7 +205,7 @@
ARA_Technology_5KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——迷雾种,一种拥有厚重甲壳的大型督虫,可以释放烟雾、阻燃剂和召唤虫族增援的信息素以协助虫群进行集群冲击。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——迷雾种,一种拥有厚重甲壳的大型督虫,可以释放烟雾、阻燃剂和召唤虫族增援的信息素以协助虫群进行集群冲击。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
800
5.50
4.80
@@ -219,7 +219,7 @@
ARA_Technology_6KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——织域种,一种寿命长且拥有强大灵能的特殊虫族,不仅能协助虫群的科研工作,也是一个强大的施法者。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——织域种,一种寿命长且拥有强大灵能的特殊虫族,不仅能协助虫群的科研工作,也是一个强大的施法者。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
800
6.50
2.70
@@ -233,7 +233,7 @@
ARA_Technology_7KYC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——禁卫种,一种寿命较其他虫族更长的精锐虫族,拥有优秀的远程作战能力和社交能力,同时也可以作为指挥官指挥虫群。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——禁卫种,一种寿命较其他虫族更长的精锐虫族,拥有优秀的远程作战能力和社交能力,同时也可以作为指挥官指挥虫群。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
2800
10.00
3.80
@@ -247,7 +247,7 @@
ARA_Technology_6MEN
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——拟线体,一种出生时躯体便已经被阿拉克涅拟线种寄生的虫族,便宜廉价并且可以快速得到的炮灰,倒是没什么纪律性就是了。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的虫族——拟线体,一种出生时躯体便已经被阿拉克涅拟线种寄生的虫族,便宜廉价并且可以快速得到的炮灰,倒是没什么纪律性就是了。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1800
7.50
2.10
@@ -572,7 +572,7 @@
ARA_Technology_5STL
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许战士种进行定向进化,抛弃其战斗技能以换取其从殖民者、囚犯和奴隶身上抽取和注入基因的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许战士种进行定向进化,抛弃其战斗技能以换取其从殖民者、囚犯和奴隶身上抽取和注入基因的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
500
4.00
4.80
@@ -583,7 +583,7 @@
ARA_Technology_1VTE
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许盾头种进行定向进化,抛弃其产出甲壳素和建造建筑的能力以换取战斗能力、移动能力和冲撞攻击的技能。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许盾头种进行定向进化,抛弃其产出甲壳素和建造建筑的能力以换取战斗能力、移动能力和冲撞攻击的技能。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1200
6.50
4.80
@@ -597,7 +597,7 @@
ARA_Technology_1MED
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许蜜罐种进行定向进化,抛弃生产虫蜜的能力,以强化其自身的医疗能力并定期产出药物。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许蜜罐种进行定向进化,抛弃生产虫蜜的能力,以强化其自身的医疗能力并定期产出药物。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1200
5.50
2.10
@@ -608,7 +608,7 @@
ARA_Technology_4CLO
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许战士种进行定向进化,牺牲其使用远程武器的能力以换取强大的近战和永久隐身的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许战士种进行定向进化,牺牲其使用远程武器的能力以换取强大的近战和永久隐身的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1800
5.50
5.30
@@ -622,7 +622,7 @@
ARA_Technology_1BAC
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许迷雾种进行定向进化,牺牲其护甲和喷射信息素的能力以换成生产虫群所需高级资源"活化钜菌"的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许迷雾种进行定向进化,牺牲其护甲和喷射信息素的能力以换成生产虫群所需高级资源"活化钜菌"的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1000
7.50
3.80
@@ -634,7 +634,7 @@
ARA_Technology_9WID
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许空天种进行定向进化,以牺牲高速和高空机动的能力换取向敌人投射大量磁暴种的能力,这种虫群可以以自杀性攻击的方式释放EMP以对抗机械族。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许空天种进行定向进化,以牺牲高速和高空机动的能力换取向敌人投射大量磁暴种的能力,这种虫群可以以自杀性攻击的方式释放EMP以对抗机械族。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1500
7.50
1.50
@@ -648,7 +648,7 @@
ARA_Technology_6LOD
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许空天种进行定向进化,以牺牲高速和高空机动的能力换取向敌人投射大量天巢种的能力,这种飞行辅虫速度很快,并且在近战中很难缠。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许空天种进行定向进化,以牺牲高速和高空机动的能力换取向敌人投射大量天巢种的能力,这种飞行辅虫速度很快,并且在近战中很难缠。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
3500
10.00
5.30
@@ -662,7 +662,7 @@
ARA_Technology_3CON
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许盾头种进行定向进化,抛弃其防御能力以换取更强大的甲壳素产出能力和建造建筑的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许盾头种进行定向进化,抛弃其防御能力以换取更强大的甲壳素产出能力和建造建筑的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
300
2.00
2.70
@@ -673,7 +673,7 @@
ARA_Technology_8FEL
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许蜜罐种进行定向进化,抛弃生产虫蜜的能力,以获得防御力增强、生产化合燃料和喷射火焰的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许蜜罐种进行定向进化,抛弃生产虫蜜的能力,以获得防御力增强、生产化合燃料和喷射火焰的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
300
2.00
2.10
@@ -684,7 +684,7 @@
ARA_Technology_3CRP
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许迷雾种进行定向进化,抛弃喷射信息素的能力,以获得防御力、移动速度的增强和大规模铺设菌毯的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许迷雾种进行定向进化,抛弃喷射信息素的能力,以获得防御力、移动速度的增强和大规模铺设菌毯的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
1300
7.50
0.90
@@ -698,7 +698,7 @@
ARA_Technology_9NAV
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许禁卫种进行定向进化,抛弃直接战斗能力和指挥地面虫群部队的能力,换取指挥空中兽虫群的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许禁卫种进行定向进化,抛弃直接战斗能力和指挥地面虫群部队的能力,换取指挥空中兽虫群的能力。\n\n阿拉克涅虫群所有需要蓝图的科技,都需要使用其触须分支特有的研究方式完成研究。
3500
11.00
3.80
@@ -846,20 +846,6 @@
-
- ARA_Technology_8SLA
-
- <color=#887E78><i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径,它们奠定了虫群在生物学上的优越性。</i></color>\n\n允许女皇种孵化新的兽虫——暴屠种。\n\n阿拉克涅虫群所有需要蓝图的科技,其研究只能通过基因试验卵进行。
- 3000
- 10.00
- 5.80
-
- ARA_Technology_2HAG
-
-
- ARA_Technology_2WMT
-
-
ARA_Technology_4COV
diff --git a/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects_Titan.xml b/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects_Titan.xml
index 941fb1c..8078c09 100644
--- a/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects_Titan.xml
+++ b/1.6/1.6/Defs/ResearchProjectDefs/ARA_ResearchProjects_Titan.xml
@@ -9,4 +9,33 @@
16.00
3.20
+
+ ARA_Technology_8SLA
+
+ <color=#915A30><i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团,包含阿拉克涅虫群中最坚韧、最具有适应力的族群,承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力,擅长以硬碰硬的模式消灭对手。</i></color>\n\n允许女皇种孵化新的兽虫——暴屠种。\n\n阿拉克涅虫群 泰坦触须所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ 3000
+ 10.00
+ 5.80
+
+ ARA_Technology_2HAG
+ ARA_Technology_2WMT
+
+
+ ARA_Titan_Base_Technology
+
+
+
+ ARA_Technology_7ACD_T
+
+ <color=#915A30><i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团,包含阿拉克涅虫群中最坚韧、最具有适应力的族群,承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力,擅长以硬碰硬的模式消灭对手。</i></color>\n\n允许蜜罐种进行定向进化,抛弃孵化辅虫的能力,换取溶解囚犯和俘虏以快速换取虫蜜的溶脂强酸。\n\n阿拉克涅虫群 泰坦触须所有需要蓝图的科技,其研究只能通过基因试验卵进行。
+ 500
+ 10.00
+ 5.80
+
+ ARA_Technology_7VXI
+
+
+ ARA_Titan_Base_Technology
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
index 4d691d4..28784b9 100644
--- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ArachnaeSwarm_Keys.xml
@@ -156,4 +156,9 @@
{0} 没有可转储的神经束负荷
无法向 {0} 转储神经束负荷
+
+ {0} 无法被选为目标
+ 目标不能被此技能影响
+
+ 需要科技 {0} 以解锁进化
\ No newline at end of file
diff --git a/About/About.xml b/About/About.xml
index dce076a..18cacb8 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -37,12 +37,7 @@
erdelf.HumanoidAlienRaces
Humanoid Alien Races 2.0
https://steamcommunity.com/sharedfiles/filedetails/?id=839005762
-
-
- Nals.FacialAnimation
- [NL] Facial Animation - WIP
- https://steamcommunity.com/sharedfiles/filedetails/?id=1635901197
-
+
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index f760c80..d991922 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 85b51d3..4c51178 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -2,6 +2,26 @@
"Version": 1,
"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\\abilities\\compabilityeffect_researchprereq.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_researchprereq.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_spawner\\hediffcompproperties_spawner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_spawner\\hediffcompproperties_spawner.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_productionqueue\\hediffcompproperties_productionqueue.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_productionqueue\\hediffcompproperties_productionqueue.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_spawner\\hediffcomp_spawner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_spawner\\hediffcomp_spawner.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_productionqueue\\hediffcomp_productionqueue.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_productionqueue\\hediffcomp_productionqueue.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}"
@@ -66,15 +86,80 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 2,
+ "SelectedChildIndex": 0,
"Children": [
+ {
+ "$type": "Document",
+ "DocumentIndex": 0,
+ "Title": "CompAbilityEffect_ResearchPrereq.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_ResearchPrereq.cs",
+ "RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_ResearchPrereq.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_ResearchPrereq.cs",
+ "RelativeToolTip": "Abilities\\CompAbilityEffect_ResearchPrereq.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAABBAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-14T07:44:51.729Z",
+ "EditorCaption": ""
+ },
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
+ "Title": "HediffCompProperties_ProductionQueue.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\HediffCompProperties_ProductionQueue.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_ProductionQueue\\HediffCompProperties_ProductionQueue.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\HediffCompProperties_ProductionQueue.cs",
+ "RelativeToolTip": "Hediffs\\ARA_ProductionQueue\\HediffCompProperties_ProductionQueue.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAAARAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-14T07:21:19.792Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 4,
+ "Title": "HediffComp_ProductionQueue.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\HediffComp_ProductionQueue.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_ProductionQueue\\HediffComp_ProductionQueue.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\HediffComp_ProductionQueue.cs",
+ "RelativeToolTip": "Hediffs\\ARA_ProductionQueue\\HediffComp_ProductionQueue.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAArAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-14T07:19:42.058Z",
+ "EditorCaption": ""
+ },
{
"$type": "Document",
"DocumentIndex": 1,
+ "Title": "HediffCompProperties_Spawner.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffCompProperties_Spawner.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_Spawner\\HediffCompProperties_Spawner.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffCompProperties_Spawner.cs",
+ "RelativeToolTip": "Hediffs\\ARA_Spawner\\HediffCompProperties_Spawner.cs",
+ "ViewState": "AgIAAFcAAAAAAAAAAADgv3gAAAApAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-14T07:09:01.203Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "HediffComp_Spawner.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
+ "RelativeToolTip": "Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
+ "ViewState": "AgIAAFwAAAAAAAAAAAAvwHEAAAAoAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-14T07:08:13.475Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 6,
"Title": "CompNodeSwarmLifetime.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
@@ -86,20 +171,20 @@
},
{
"$type": "Document",
- "DocumentIndex": 0,
+ "DocumentIndex": 5,
"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": "AgIAAAAAAAAAAAAAAAAAAA4AAAAnAAAAAAAAAA==",
+ "ViewState": "AgIAABMAAAAAAAAAAAAAwBUAAAAVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-14T02:36:39.249Z",
"EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 4,
+ "DocumentIndex": 9,
"Title": "ARA_DefOf.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
"RelativeDocumentMoniker": "ARA_DefOf.cs",
@@ -111,7 +196,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 5,
+ "DocumentIndex": 10,
"Title": "JobDriver_CastAbilityMaintainMultiProjectile.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_LaunchMultiProjectile\\JobDriver_CastAbilityMaintainMultiProjectile.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_LaunchMultiProjectile\\JobDriver_CastAbilityMaintainMultiProjectile.cs",
@@ -123,7 +208,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 7,
"Title": "CompProperties_AbilityLaunchMultiProjectile.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_LaunchMultiProjectile\\CompProperties_AbilityLaunchMultiProjectile.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_LaunchMultiProjectile\\CompProperties_AbilityLaunchMultiProjectile.cs",
@@ -135,7 +220,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 6,
+ "DocumentIndex": 11,
"Title": "CompAbilityEffect_Transform.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_Morphable\\CompAbilityEffect_Transform.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_Morphable\\CompAbilityEffect_Transform.cs",
@@ -147,7 +232,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 8,
"Title": "CompAbilityEffect_LaunchMultiProjectile.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_LaunchMultiProjectile\\CompAbilityEffect_LaunchMultiProjectile.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_LaunchMultiProjectile\\CompAbilityEffect_LaunchMultiProjectile.cs",
@@ -159,7 +244,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 8,
+ "DocumentIndex": 13,
"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",
@@ -171,7 +256,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 9,
+ "DocumentIndex": 14,
"Title": "Gizmo_PawnResearchProgress.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Gizmo_PawnResearchProgress.cs",
@@ -183,7 +268,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 7,
+ "DocumentIndex": 12,
"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",
@@ -195,7 +280,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 12,
+ "DocumentIndex": 17,
"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",
@@ -207,7 +292,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 11,
+ "DocumentIndex": 16,
"Title": "Gizmo_ResearchProgress.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\Gizmo_ResearchProgress.cs",
"RelativeDocumentMoniker": "Buildings\\Building_ResearchBlueprintReader\\Gizmo_ResearchProgress.cs",
@@ -219,7 +304,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 13,
+ "DocumentIndex": 18,
"Title": "ResearchBlueprintData.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintData.cs",
"RelativeDocumentMoniker": "Buildings\\Building_ResearchBlueprintReader\\ResearchBlueprintData.cs",
@@ -231,7 +316,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 10,
+ "DocumentIndex": 15,
"Title": "Comp_PawnResearchBlueprintReader.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_PawnResearchBlueprintReader\\Comp_PawnResearchBlueprintReader.cs",
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompAbilityEffect_HediffBlacklist.cs b/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompAbilityEffect_HediffBlacklist.cs
new file mode 100644
index 0000000..bee398c
--- /dev/null
+++ b/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompAbilityEffect_HediffBlacklist.cs
@@ -0,0 +1,62 @@
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompAbilityEffect_HediffBlacklist : CompAbilityEffect
+ {
+ public new CompProperties_AbilityHediffBlacklist Props => (CompProperties_AbilityHediffBlacklist)props;
+
+ public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
+ {
+ Pawn targetPawn = target.Pawn;
+
+ // 如果不是Pawn,返回父类验证结果
+ if (targetPawn == null)
+ return base.Valid(target, throwMessages);
+
+ // 检查目标是否拥有黑名单中的任意一个Hediff
+ if (HasBlacklistedHediff(targetPawn))
+ {
+ if (throwMessages)
+ {
+ Messages.Message(Props.blockedMessage.Translate(targetPawn.LabelShort),
+ targetPawn, MessageTypeDefOf.RejectInput, false);
+ }
+ return false;
+ }
+
+ return base.Valid(target, throwMessages);
+ }
+
+ ///
+ /// 检查目标Pawn是否拥有黑名单中的任意一个Hediff
+ ///
+ private bool HasBlacklistedHediff(Pawn pawn)
+ {
+ if (pawn?.health?.hediffSet == null || Props.blacklistedHediffs.NullOrEmpty())
+ return false;
+
+ foreach (HediffDef hediffDef in Props.blacklistedHediffs)
+ {
+ if (hediffDef != null && pawn.health.hediffSet.HasHediff(hediffDef))
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 在能力描述中显示黑名单信息
+ ///
+ public override string ExtraLabelMouseAttachment(LocalTargetInfo target)
+ {
+ Pawn targetPawn = target.Pawn;
+ if (targetPawn != null && HasBlacklistedHediff(targetPawn))
+ {
+ return "CannotTargetPawnWithBlacklistedHediff".Translate();
+ }
+ return null;
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompProperties_AbilityHediffBlacklist.cs b/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompProperties_AbilityHediffBlacklist.cs
new file mode 100644
index 0000000..409b00e
--- /dev/null
+++ b/Source/ArachnaeSwarm/Abilities/ARA_HediffBlacklist/CompProperties_AbilityHediffBlacklist.cs
@@ -0,0 +1,24 @@
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_AbilityHediffBlacklist : CompProperties_AbilityEffect
+ {
+ ///
+ /// 黑名单Hediff列表,拥有这些Hediff的Pawn无法成为目标
+ ///
+ public List blacklistedHediffs;
+
+ ///
+ /// 目标被阻止时显示的消息
+ ///
+ public string blockedMessage = "ARA_BlacklistedHediff_Blocked";
+
+ public CompProperties_AbilityHediffBlacklist()
+ {
+ this.compClass = typeof(CompAbilityEffect_HediffBlacklist);
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Abilities/PsychicBrainburn/CompAbilityEffect_PsychicBrainburn.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicBrainburn/CompAbilityEffect_PsychicBrainburn.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/PsychicBrainburn/CompAbilityEffect_PsychicBrainburn.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_PsychicBrainburn/CompAbilityEffect_PsychicBrainburn.cs
diff --git a/Source/ArachnaeSwarm/Abilities/PsychicBrainburn/CompProperties_PsychicBrainburn.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicBrainburn/CompProperties_PsychicBrainburn.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/PsychicBrainburn/CompProperties_PsychicBrainburn.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_PsychicBrainburn/CompProperties_PsychicBrainburn.cs
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_SprayLiquidMulti.cs b/Source/ArachnaeSwarm/Abilities/ARA_SprayLiquidMulti/CompAbilityEffect_SprayLiquidMulti.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_SprayLiquidMulti.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_SprayLiquidMulti/CompAbilityEffect_SprayLiquidMulti.cs
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompProperties_AbilitySprayLiquidMulti.cs b/Source/ArachnaeSwarm/Abilities/ARA_SprayLiquidMulti/CompProperties_AbilitySprayLiquidMulti.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompProperties_AbilitySprayLiquidMulti.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_SprayLiquidMulti/CompProperties_AbilitySprayLiquidMulti.cs
diff --git a/Source/ArachnaeSwarm/Abilities/TrackingCharge/CompAbilityEffect_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/CompAbilityEffect_TrackingCharge.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/TrackingCharge/CompAbilityEffect_TrackingCharge.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/CompAbilityEffect_TrackingCharge.cs
diff --git a/Source/ArachnaeSwarm/Abilities/TrackingCharge/CompProperties_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/CompProperties_TrackingCharge.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/TrackingCharge/CompProperties_TrackingCharge.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/CompProperties_TrackingCharge.cs
diff --git a/Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/PawnFlyer_TrackingCharge.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/TrackingCharge/PawnFlyer_TrackingCharge.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/PawnFlyer_TrackingCharge.cs
diff --git a/Source/ArachnaeSwarm/Abilities/TrackingCharge/Verb_CastAbilityTrackingCharge.cs b/Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/Verb_CastAbilityTrackingCharge.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/TrackingCharge/Verb_CastAbilityTrackingCharge.cs
rename to Source/ArachnaeSwarm/Abilities/ARA_TrackingCharge/Verb_CastAbilityTrackingCharge.cs
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_BodyPartCheck.cs b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_BodyPartCheck.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_BodyPartCheck.cs
rename to Source/ArachnaeSwarm/Abilities/CompAbilityEffect_BodyPartCheck.cs
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_NeedCost.cs b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_NeedCost.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_NeedCost.cs
rename to Source/ArachnaeSwarm/Abilities/CompAbilityEffect_NeedCost.cs
diff --git a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_ResearchPrereq.cs b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ResearchPrereq.cs
similarity index 85%
rename from Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_ResearchPrereq.cs
rename to Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ResearchPrereq.cs
index f2c9a5d..7d39b28 100644
--- a/Source/ArachnaeSwarm/Abilities/ARA_QueenAbility/CompAbilityEffect_ResearchPrereq.cs
+++ b/Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ResearchPrereq.cs
@@ -6,7 +6,7 @@ namespace ArachnaeSwarm
public class CompProperties_AbilityResearchPrereq : CompProperties_AbilityEffect
{
public ResearchProjectDef requiredResearch;
- public string failMessage = "Research not completed.";
+ public string failMessage;
public CompProperties_AbilityResearchPrereq()
{
@@ -22,7 +22,7 @@ namespace ArachnaeSwarm
{
if (Props.requiredResearch != null && !Props.requiredResearch.IsFinished)
{
- reason = Props.failMessage;
+ reason = Props.failMessage ?? "ARA_AbilityRequiresTech".Translate(Props.requiredResearch);
return true;
}
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 433d4c6..efd4f06 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -118,11 +118,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -134,12 +134,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -309,9 +309,8 @@
-
-
-
+
+
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffCompProperties_Spawner.cs b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffCompProperties_Spawner.cs
new file mode 100644
index 0000000..3a4376f
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffCompProperties_Spawner.cs
@@ -0,0 +1,123 @@
+using System;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class HediffCompProperties_Spawner : HediffCompProperties
+ {
+ public HediffCompProperties_Spawner()
+ {
+ this.compClass = typeof(HediffComp_Spawner);
+ }
+
+ ///
+ /// 要生成的物品的ThingDef。如果animalThing为false,则使用此项。
+ ///
+ public ThingDef thingToSpawn;
+
+ ///
+ /// 每次生成的基础物品数量。
+ ///
+ public int spawnCount = 1;
+
+ ///
+ /// 如果为true,则生成一个Pawn(动物)。如果为false,则生成一个Thing。
+ ///
+ public bool animalThing;
+
+ ///
+ /// 要生成的动物的PawnKindDef。如果animalThing为true,则使用此项。
+ ///
+ public PawnKindDef animalToSpawn;
+
+ ///
+ /// 如果为true,生成的动物将属于玩家派系。
+ ///
+ public bool factionOfPlayerAnimal;
+
+ ///
+ /// 下一次生成事件发生前的最少天数。
+ ///
+ public float minDaysB4Next = 1f;
+
+ ///
+ /// 下一次生成事件发生前的最大天数。
+ ///
+ public float maxDaysB4Next = 2f;
+
+ ///
+ /// 生成后进入宽限期(延迟下一次生成)的几率(0.0到1.0)。
+ ///
+ public float randomGrace;
+
+ ///
+ /// 如果触发,宽限期的持续时间(天)。
+ ///
+ public float graceDays = 0.5f;
+
+ ///
+ /// 附近允许的相同Pawn的最大数量。如果超过该数量,则暂停生成。-1为禁用。
+ ///
+ public int spawnMaxAdjacent = -1;
+
+ ///
+ /// 如果为true,生成的物品将被禁用。
+ ///
+ public bool spawnForbidden;
+
+ ///
+ /// 如果为true,当宿主Pawn饥饿时,生成将暂停。
+ ///
+ public bool hungerRelative;
+
+ ///
+ /// 如果为true,当宿主Pawn受伤时,生成将暂停。
+ ///
+ public bool healthRelative;
+
+ ///
+ /// 如果为true,生成数量将根据宿主的年龄进行调整。
+ ///
+ public bool ageWeightedQuantity;
+
+ ///
+ /// 如果为true,生成周期(两次生成之间的时间)将根据宿主的年龄进行调整。
+ ///
+ public bool ageWeightedPeriod;
+
+ ///
+ /// 如果为true且ageWeightedPeriod为true,则随着宿主年龄增长,生成周期变短。如果为false,则变长。
+ ///
+ public bool olderSmallerPeriod;
+
+ ///
+ /// 如果为true且ageWeightedQuantity为true,则随着宿主年龄增长,生成数量变多。如果为false,则变少。
+ ///
+ public bool olderBiggerQuantity;
+
+ ///
+ /// 如果为true且ageWeightedQuantity为true,则随年龄增长的数量缩放将是指数性的而非线性的。
+ ///
+ public bool exponentialQuantity;
+
+ ///
+ /// 指数级数量缩放的最大乘数,以防止出现荒谬的数字。
+ ///
+ public int exponentialRatioLimit = 15;
+
+ ///
+ /// 生成时显示的消息的翻译键(例如,"下了一个蛋")。
+ ///
+ public string spawnVerb = "delivery";
+
+ ///
+ /// 如果为true,则为此组件启用详细的调试日志记录。
+ ///
+ public bool debug;
+
+ ///
+ /// 新增:生成物品时是否销毁随机身体部位
+ ///
+ public bool destroyRandomBodyPart = false;
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs
new file mode 100644
index 0000000..6e3f1d8
--- /dev/null
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_Spawner/HediffComp_Spawner.cs
@@ -0,0 +1,883 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using RimWorld.Planet;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class HediffComp_Spawner : HediffComp
+ {
+ public HediffCompProperties_Spawner Props
+ {
+ get
+ {
+ return (HediffCompProperties_Spawner)this.props;
+ }
+ }
+
+ public override void CompExposeData()
+ {
+ Scribe_Values.Look(ref this.ticksUntilSpawn, "ticksUntilSpawn", 0, false);
+ Scribe_Values.Look(ref this.initialTicksUntilSpawn, "initialTicksUntilSpawn", 0, false);
+ Scribe_Values.Look(ref this.calculatedMinDaysB4Next, "calculatedMinDaysB4Next", 0f, false);
+ Scribe_Values.Look(ref this.calculatedMaxDaysB4Next, "calculatedMaxDaysB4Next", 0f, false);
+ Scribe_Values.Look(ref this.calculatedQuantity, "calculatedQuantity", 0, false);
+ Scribe_Values.Look(ref this.graceTicks, "graceTicks", 0, false);
+ }
+
+ public override void CompPostMake()
+ {
+ this.myDebug = this.Props.debug;
+ Warn(string.Concat(new string[]
+ {
+ ">>> ",
+ this.parent.pawn.Label,
+ " - ",
+ this.parent.def.defName,
+ " - CompPostMake start"
+ }), this.myDebug);
+ TraceProps();
+ CheckProps();
+ CalculateValues();
+ CheckCalculatedValues();
+ TraceCalculatedValues();
+ if (this.initialTicksUntilSpawn == 0)
+ {
+ Warn("Reseting countdown bc initialTicksUntilSpawn == 0 (comppostmake)", this.myDebug);
+ ResetCountdown();
+ }
+ }
+
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ this.pawn = this.parent.pawn;
+ if (!OkPawn(this.pawn))
+ {
+ return;
+ }
+ if (this.blockSpawn)
+ {
+ return;
+ }
+ if (this.graceTicks > 0)
+ {
+ this.graceTicks--;
+ return;
+ }
+ if (this.Props.hungerRelative && this.pawn.Starving())
+ {
+ int num = (int)(this.RandomGraceDays() * 60000f);
+ this.hungerReset++;
+ this.graceTicks = num;
+ return;
+ }
+ if (this.Props.healthRelative && this.pawn.Starving())
+ {
+ int num2 = (int)(this.RandomGraceDays() * 60000f);
+ this.healthReset++;
+ this.graceTicks = num2;
+ return;
+ }
+ this.hungerReset = (this.healthReset = 0);
+ if (this.CheckShouldSpawn())
+ {
+ Warn("Reseting countdown bc spawned thing", this.myDebug);
+ CalculateValues();
+ CheckCalculatedValues();
+ ResetCountdown();
+ if (Rand.Chance(this.Props.randomGrace))
+ {
+ int num3 = (int)(this.RandomGraceDays() * 60000f);
+ this.graceTicks = num3;
+ }
+ }
+ }
+
+ private void TraceProps()
+ {
+ Warn(string.Concat(new string[]
+ {
+ "Props => minDaysB4Next: ",
+ this.Props.minDaysB4Next.ToString(),
+ "; maxDaysB4Next: ",
+ this.Props.maxDaysB4Next.ToString(),
+ "; randomGrace: ",
+ this.Props.randomGrace.ToString(),
+ "; graceDays: ",
+ this.Props.graceDays.ToString(),
+ "; hungerRelative: ",
+ this.Props.hungerRelative.ToString(),
+ "; healthRelative: ",
+ this.Props.healthRelative.ToString(),
+ "; destroyRandomBodyPart: ",
+ this.Props.destroyRandomBodyPart.ToString(),
+ "; "
+ }), this.myDebug);
+ if (this.Props.animalThing)
+ {
+ Warn(string.Concat(new string[]
+ {
+ "animalThing: ",
+ this.Props.animalThing.ToString(),
+ "; animalName: ",
+ this.Props.animalToSpawn.defName,
+ "; factionOfPlayerAnimal: ",
+ this.Props.factionOfPlayerAnimal.ToString(),
+ "; "
+ }), this.myDebug);
+ }
+ if (this.Props.ageWeightedQuantity)
+ {
+ Warn(string.Concat(new string[]
+ {
+ "ageWeightedQuantity:",
+ this.Props.ageWeightedQuantity.ToString(),
+ "; olderBiggerQuantity:",
+ this.Props.olderBiggerQuantity.ToString(),
+ "; ",
+ this.myDebug.ToString()
+ }), false);
+ if (this.Props.exponentialQuantity)
+ {
+ Warn(string.Concat(new string[]
+ {
+ "exponentialQuantity:",
+ this.Props.exponentialQuantity.ToString(),
+ "; exponentialRatioLimit:",
+ this.Props.exponentialRatioLimit.ToString(),
+ "; "
+ }), this.myDebug);
+ }
+ }
+ Warn(string.Concat(new string[]
+ {
+ "ageWeightedPeriod:",
+ this.Props.ageWeightedPeriod.ToString(),
+ "; olderSmallerPeriod:",
+ this.Props.olderSmallerPeriod.ToString(),
+ "; ",
+ this.myDebug.ToString()
+ }), false);
+ }
+
+ private void CalculateValues()
+ {
+ float num = GetPawnAgeOverlifeExpectancyRatio(this.parent.pawn, this.myDebug);
+ num = ((num > 1f) ? 1f : num);
+ this.calculatedMinDaysB4Next = this.Props.minDaysB4Next;
+ this.calculatedMaxDaysB4Next = this.Props.maxDaysB4Next;
+ if (this.Props.ageWeightedPeriod)
+ {
+ float num2 = this.Props.olderSmallerPeriod ? (-num) : num;
+ this.calculatedMinDaysB4Next = this.Props.minDaysB4Next * (1f + num2);
+ this.calculatedMaxDaysB4Next = this.Props.maxDaysB4Next * (1f + num2);
+ Warn(string.Concat(new string[]
+ {
+ " ageWeightedPeriod: ",
+ this.Props.ageWeightedPeriod.ToString(),
+ " ageRatio: ",
+ num.ToString(),
+ " minDaysB4Next: ",
+ this.Props.minDaysB4Next.ToString(),
+ " maxDaysB4Next: ",
+ this.Props.maxDaysB4Next.ToString(),
+ " daysAgeRatio: ",
+ num2.ToString(),
+ " calculatedMinDaysB4Next: ",
+ this.calculatedMinDaysB4Next.ToString(),
+ "; calculatedMaxDaysB4Next: ",
+ this.calculatedMaxDaysB4Next.ToString(),
+ "; "
+ }), this.myDebug);
+ }
+ this.calculatedQuantity = this.Props.spawnCount;
+ if (this.Props.ageWeightedQuantity)
+ {
+ float num3 = this.Props.olderBiggerQuantity ? num : (-num);
+ Warn("quantityAgeRatio: " + num3.ToString(), this.myDebug);
+ this.calculatedQuantity = (int)Math.Round((double)this.Props.spawnCount * (double)(1f + num3));
+ if (this.Props.exponentialQuantity)
+ {
+ num3 = 1f - num;
+ if (num3 == 0f)
+ {
+ Warn(">ERROR< quantityAgeRatio is f* up : " + num3.ToString(), this.myDebug);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ float num4 = this.Props.olderBiggerQuantity ? (1f / num3) : (num3 * num3);
+ bool flag = false;
+ bool flag2 = false;
+ if (num4 > (float)this.Props.exponentialRatioLimit)
+ {
+ num4 = (float)this.Props.exponentialRatioLimit;
+ flag = true;
+ }
+ this.calculatedQuantity = (int)Math.Round((double)this.Props.spawnCount * (double)num4);
+ if (this.calculatedQuantity < 1)
+ {
+ this.calculatedQuantity = 1;
+ flag2 = true;
+ }
+ Warn(string.Concat(new string[]
+ {
+ " exponentialQuantity: ",
+ this.Props.exponentialQuantity.ToString(),
+ "; expoFactor: ",
+ num4.ToString(),
+ "; gotLimited: ",
+ flag.ToString(),
+ "; gotAugmented: ",
+ flag2.ToString()
+ }), this.myDebug);
+ }
+ Warn("; Props.spawnCount: " + this.Props.spawnCount.ToString() + "; calculatedQuantity: " + this.calculatedQuantity.ToString(), this.myDebug);
+ }
+ }
+
+ private void CheckCalculatedValues()
+ {
+ if (this.calculatedQuantity > this.errorSpawnCount)
+ {
+ Warn(string.Concat(new string[]
+ {
+ ">ERROR< calculatedQuantity is too high: ",
+ this.calculatedQuantity.ToString(),
+ "(>",
+ this.errorSpawnCount.ToString(),
+ "), check and adjust your hediff props"
+ }), this.myDebug);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.calculatedMinDaysB4Next < this.errorMinDaysB4Next)
+ {
+ this.calculatedMinDaysB4Next = this.errorMinDaysB4Next;
+ }
+ if (this.calculatedMaxDaysB4Next < this.errorMinDaysB4Next)
+ {
+ this.calculatedMaxDaysB4Next = this.errorMinDaysB4Next;
+ }
+ }
+
+ private void TraceCalculatedValues()
+ {
+ Warn("calculatedMinDaysB4Next:" + this.calculatedMinDaysB4Next.ToString(), this.myDebug);
+ Warn("calculatedMaxDaysB4Next:" + this.calculatedMaxDaysB4Next.ToString(), this.myDebug);
+ Warn("calculatedQuantity:" + this.calculatedQuantity.ToString(), this.myDebug);
+ }
+
+ private void CheckProps()
+ {
+ if (this.Props.animalThing && this.Props.animalToSpawn == null)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with animalflag but without animalToSpawn", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.Props.minDaysB4Next <= 0f)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative minDaysB4Next", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.Props.maxDaysB4Next <= 0f)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative maxDaysB4Next", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.Props.maxDaysB4Next < this.Props.minDaysB4Next)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with maxDaysB4Next < minDaysB4Next", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.Props.spawnCount <= 0)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative spawnCount", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (!this.Props.animalThing && this.Props.thingToSpawn == null)
+ {
+ Warn(this.parent.pawn.Label + " has a hediffcomp_spawner without thingToSpawn", true);
+ this.blockSpawn = true;
+ DestroyParentHediff(this.parent, this.myDebug);
+ return;
+ }
+ if (this.Props.ageWeightedQuantity && this.Props.exponentialQuantity && this.Props.exponentialRatioLimit > this.errorExponentialLimit)
+ {
+ Warn(string.Concat(new string[]
+ {
+ this.parent.pawn.Label,
+ " has a hediffcomp_spawner with exponentialRatioLimit>",
+ this.errorExponentialLimit.ToString(),
+ " this is not allowed. It will be set to ",
+ this.errorExponentialLimit.ToString()
+ }), true);
+ this.Props.exponentialRatioLimit = this.errorExponentialLimit;
+ }
+ }
+
+ private bool CheckShouldSpawn()
+ {
+ this.ticksUntilSpawn--;
+ if (this.ticksUntilSpawn <= 0)
+ {
+ if (this.TryDoSpawn())
+ {
+ return true;
+ }
+ Warn("Did not spawn, reseting countdown", this.myDebug);
+ ResetCountdown();
+ }
+ return false;
+ }
+
+ public bool TryDoSpawn()
+ {
+ Pawn pawn = this.parent.pawn;
+
+ if (this.Props.animalThing)
+ {
+ // 动物生成逻辑保持不变
+ if (this.Props.spawnMaxAdjacent > 0 && pawn.Map.mapPawns.AllPawns.Where(delegate(Pawn mP)
+ {
+ ThingDef defToCompare = this.Props.animalThing ? this.Props.animalToSpawn?.race : this.Props.thingToSpawn;
+ if (defToCompare?.race == null)
+ {
+ return false;
+ }
+ return mP.def == defToCompare && mP.Position.InHorDistOf(pawn.Position, (float)this.Props.spawnMaxAdjacent);
+ }).Count() >= this.Props.spawnMaxAdjacent)
+ {
+ return false;
+ }
+
+ if (this.Props.animalToSpawn == null)
+ {
+ return false;
+ }
+
+ Faction faction = this.Props.factionOfPlayerAnimal ? Faction.OfPlayer : null;
+ int i = 0;
+ while (i < this.calculatedQuantity)
+ {
+ IntVec3 intVec;
+ if (!this.TryFindSpawnCell(out intVec))
+ {
+ return false;
+ }
+ Pawn pawn2 = PawnGenerator.GeneratePawn(this.Props.animalToSpawn, faction);
+ if (pawn2 == null)
+ {
+ return false;
+ }
+ GenSpawn.Spawn(pawn2, intVec, pawn.Map, WipeMode.Vanish);
+ pawn2.SetFaction(faction, null);
+ FilthMaker.TryMakeFilth(intVec, pawn.Map, ThingDefOf.Filth_AmnioticFluid, pawn.LabelIndefinite(), 5, FilthSourceFlags.None);
+ if (!this.Props.spawnForbidden)
+ {
+ pawn2.playerSettings.Master = pawn;
+ pawn2.training.Train(TrainableDefOf.Obedience, pawn, true);
+ }
+ i++;
+ continue;
+ }
+ if (PawnUtility.ShouldSendNotificationAbout(pawn) || PawnUtility.ShouldSendNotificationAbout(pawn))
+ {
+ Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.PositiveEvent, true);
+ }
+ return true;
+ }
+ else
+ {
+ // 重新设计物品生成逻辑:按优先级顺序尝试
+ bool success = TrySpawnItemWithPriority(pawn);
+
+ // === 新增:如果配置了销毁随机部位,在成功生成物品后执行 ===
+ if (success && this.Props.destroyRandomBodyPart)
+ {
+ DestroyRandomBodyPart(pawn);
+ }
+
+ return success;
+ }
+ }
+
+ // 新增:销毁随机身体部位(参考 CompAbilityEffect_DestroyOwnBodyPart)
+ private void DestroyRandomBodyPart(Pawn pawn)
+ {
+ try
+ {
+ if (pawn == null || pawn.Dead)
+ {
+ Warn($"Cannot destroy body part for null or dead pawn", this.myDebug);
+ return;
+ }
+
+ // 获取所有可以销毁的身体部位
+ List possibleParts = GetDestroyableBodyParts(pawn);
+
+ if (possibleParts.Count == 0)
+ {
+ Warn($"No destroyable body parts found for {pawn.LabelShort}", this.myDebug);
+ return;
+ }
+
+ // 随机选择一个部位
+ BodyPartRecord partToDestroy = possibleParts.RandomElement();
+
+ if (partToDestroy == null)
+ {
+ Warn($"Selected null body part for {pawn.LabelShort}", this.myDebug);
+ return;
+ }
+
+ // 记录部位名称
+ string partName = partToDestroy.def?.label ?? "未知部位";
+
+ // 添加缺失部位hediff
+ pawn.health.AddHediff(HediffDefOf.MissingBodyPart, partToDestroy);
+
+ Warn($"Destroyed {partName} on {pawn.LabelShort}", this.myDebug);
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error destroying random body part for {pawn?.LabelShort}: {ex.Message}");
+ }
+ }
+
+ // 新增:获取可以销毁的身体部位列表
+ private List GetDestroyableBodyParts(Pawn pawn)
+ {
+ List destroyableParts = new List();
+
+ if (pawn?.health?.hediffSet == null)
+ return destroyableParts;
+
+ // 获取所有身体部位
+ List allParts = pawn.RaceProps.body.AllParts;
+
+ foreach (BodyPartRecord part in allParts)
+ {
+ // 排除核心部位(避免死亡)
+ if (IsCriticalBodyPart(part))
+ continue;
+
+ // 排除已经缺失的部位
+ if (pawn.health.hediffSet.PartIsMissing(part))
+ continue;
+
+ // 排除已经有严重伤害的部位(可选)
+ if (pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part))
+ continue;
+
+ destroyableParts.Add(part);
+ }
+
+ return destroyableParts;
+ }
+
+ // 新增:检查是否是关键身体部位
+ private bool IsCriticalBodyPart(BodyPartRecord part)
+ {
+ if (part == null)
+ return false;
+
+ // 根据标签判断是否为关键部位
+ if (part.def.tags != null)
+ {
+ // 这些标签通常表示关键部位
+ if (part.def.tags.Contains(BodyPartTagDefOf.ConsciousnessSource) || // 意识源(大脑)
+ part.def.tags.Contains(BodyPartTagDefOf.BloodPumpingSource) || // 血液泵源(心脏)
+ part.def.tags.Contains(BodyPartTagDefOf.BreathingSource) || // 呼吸源(肺)
+ part.def.tags.Contains(BodyPartTagDefOf.MetabolismSource) // 代谢源(肝脏)
+ )
+ {
+ return true;
+ }
+ }
+
+ // 根据深度判断(深度较深的通常是内部器官)
+ if (part.depth == BodyPartDepth.Inside && part.parent == null)
+ return true;
+
+ return false;
+ }
+
+ // 新增:按优先级顺序尝试生成物品
+ private bool TrySpawnItemWithPriority(Pawn pawn)
+ {
+ Thing thing = ThingMaker.MakeThing(this.Props.thingToSpawn, null);
+ if (thing == null)
+ {
+ Warn("Failed to create thing: " + this.Props.thingToSpawn?.defName, this.myDebug);
+ return false;
+ }
+ thing.stackCount = this.calculatedQuantity;
+
+ // 记录原始物品用于校验
+ ThingDef originalThingDef = thing.def;
+ int originalStackCount = thing.stackCount;
+
+ // 按优先级顺序尝试生成
+ bool success = false;
+ string spawnMethod = "";
+
+ // 优先级1: 尝试在pawn附近空地生成
+ if (!success)
+ {
+ success = TrySpawnAtNearbyEmptyCell(pawn, thing, ref spawnMethod);
+ }
+
+ // 优先级2: 尝试在pawn脚底生成
+ if (!success)
+ {
+ success = TrySpawnAtPawnPosition(pawn, thing, ref spawnMethod);
+ }
+
+ // 优先级3: 尝试放入pawn物品栏
+ if (!success)
+ {
+ success = TrySpawnInInventory(pawn, thing, ref spawnMethod);
+ }
+
+ // 生成后校验
+ if (success)
+ {
+ bool verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, spawnMethod);
+
+ // 如果校验失败且不是在物品栏中生成的,尝试在物品栏中重新生成
+ if (!verified && spawnMethod != "inventory")
+ {
+ Warn($"Spawn verification failed for {spawnMethod}, attempting inventory fallback", this.myDebug);
+
+ // 重新创建物品
+ Thing fallbackThing = ThingMaker.MakeThing(originalThingDef, null);
+ fallbackThing.stackCount = originalStackCount;
+
+ success = TrySpawnInInventory(pawn, fallbackThing, ref spawnMethod);
+
+ if (success)
+ {
+ verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, "inventory_fallback");
+ if (!verified)
+ {
+ Warn("Inventory fallback also failed verification", this.myDebug);
+ success = false;
+ }
+ }
+ }
+
+ if (success && verified)
+ {
+ if (PawnUtility.ShouldSendNotificationAbout(pawn))
+ {
+ Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN"), thing.Named("THING")),
+ spawnMethod == "inventory" || spawnMethod == "inventory_fallback" ? pawn : thing,
+ MessageTypeDefOf.PositiveEvent, true);
+ }
+ Warn($"Successfully spawned {originalStackCount}x {originalThingDef.defName} via {spawnMethod}", this.myDebug);
+ return true;
+ }
+ }
+
+ Warn($"Failed to spawn {originalStackCount}x {originalThingDef.defName} after all attempts", this.myDebug);
+ return false;
+ }
+
+ // 新增:尝试在附近空地生成
+ private bool TrySpawnAtNearbyEmptyCell(Pawn pawn, Thing thing, ref string spawnMethod)
+ {
+ IntVec3 spawnCell;
+ if (TryFindSpawnCell(out spawnCell))
+ {
+ if (this.Props.spawnForbidden)
+ {
+ thing.SetForbidden(true, true);
+ }
+
+ if (GenPlace.TryPlaceThing(thing, spawnCell, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4)))
+ {
+ spawnMethod = "nearby_cell";
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // 新增:尝试在pawn位置生成
+ private bool TrySpawnAtPawnPosition(Pawn pawn, Thing thing, ref string spawnMethod)
+ {
+ IntVec3 pawnPosition = pawn.Position;
+ if (pawnPosition.IsValid && pawnPosition.Walkable(pawn.Map))
+ {
+ if (this.Props.spawnForbidden)
+ {
+ thing.SetForbidden(true, true);
+ }
+
+ if (GenPlace.TryPlaceThing(thing, pawnPosition, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4)))
+ {
+ spawnMethod = "pawn_position";
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // 新增:尝试在物品栏生成
+ private bool TrySpawnInInventory(Pawn pawn, Thing thing, ref string spawnMethod)
+ {
+ if (pawn.inventory == null)
+ {
+ Warn($"Pawn {pawn.Label} does not have an inventory", this.myDebug);
+ return false;
+ }
+
+ if (pawn.inventory.innerContainer.TryAdd(thing))
+ {
+ spawnMethod = "inventory";
+ return true;
+ }
+ return false;
+ }
+
+ // 新增:生成后校验
+ private bool VerifySpawnSuccess(Pawn pawn, ThingDef thingDef, int expectedCount, string spawnMethod)
+ {
+ bool verificationSuccess = false;
+
+ switch (spawnMethod)
+ {
+ case "nearby_cell":
+ case "pawn_position":
+ case "inventory_fallback":
+ // 检查地图上是否有生成的物品
+ verificationSuccess = pawn.Map.listerThings.ThingsOfDef(thingDef)
+ .Any(t => t.stackCount >= expectedCount && t.Position.InHorDistOf(pawn.Position, 2f));
+ break;
+
+ case "inventory":
+ // 检查物品栏中是否有生成的物品
+ verificationSuccess = pawn.inventory.innerContainer.Any(t => t.def == thingDef && t.stackCount >= expectedCount);
+ break;
+ }
+
+ if (!verificationSuccess)
+ {
+ Warn($"Spawn verification failed for {thingDef.defName} via {spawnMethod}", this.myDebug);
+ }
+ else
+ {
+ Warn($"Spawn verification successful for {thingDef.defName} via {spawnMethod}", this.myDebug);
+ }
+
+ return verificationSuccess;
+ }
+
+ private bool TryFindSpawnCell(out IntVec3 result)
+ {
+ result = IntVec3.Invalid;
+ bool result2;
+ if (this.pawn == null)
+ {
+ result2 = false;
+ }
+ else
+ {
+ Map map = this.pawn.Map;
+ if (map == null)
+ {
+ result2 = false;
+ }
+ else
+ {
+ // 修改这里:将半径从5减少到2,让生成位置更靠近pawn
+ int searchRadius = 2;
+
+ // 首先尝试在pawn的相邻单元格生成(半径为1)
+ result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, 1, null);
+
+ // 如果相邻单元格找不到合适位置,再尝试稍远一点(半径为2)
+ if (!result.IsValid)
+ {
+ result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, searchRadius, null);
+ }
+
+ // 如果还是找不到,尝试pawn当前位置(作为最后手段)
+ if (!result.IsValid && this.pawn.Position.IsValid && this.pawn.Position.Walkable(map))
+ {
+ result = this.pawn.Position;
+ }
+
+ result2 = result.IsValid;
+ }
+ }
+ return result2;
+ }
+
+ private void ResetCountdown()
+ {
+ this.ticksUntilSpawn = (int)(this.RandomDays2wait() * 60000f);
+ this.initialTicksUntilSpawn = this.ticksUntilSpawn;
+ }
+
+ private float RandomDays2wait()
+ {
+ return Rand.Range(this.calculatedMinDaysB4Next, this.calculatedMaxDaysB4Next);
+ }
+
+ private float RandomGraceDays()
+ {
+ return Rand.Range(this.Props.graceDays / 2f, this.Props.graceDays);
+ }
+
+ public override string CompTipStringExtra
+ {
+ get
+ {
+ if (!this.myDebug)
+ {
+ return null;
+ }
+ string text = "ticksUntilSpawn: " + this.ticksUntilSpawn.ToString() + "\n";
+ string text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "initialTicksUntilSpawn: ",
+ this.initialTicksUntilSpawn.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "graceTicks: ",
+ this.graceTicks.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "hunger resets: ",
+ this.hungerReset.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "health resets: ",
+ this.healthReset.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "calculatedMinDaysB4Next: ",
+ this.calculatedMinDaysB4Next.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "calculatedMaxDaysB4Next: ",
+ this.calculatedMaxDaysB4Next.ToString(),
+ "\n"
+ });
+ text2 = text;
+ text = string.Concat(new string[]
+ {
+ text2,
+ "calculatedQuantity: ",
+ this.calculatedQuantity.ToString(),
+ "\n"
+ });
+ return text + "blockSpawn: " + this.blockSpawn.ToString();
+ }
+ }
+
+ // === 整合的 Tools 方法 ===
+
+ private void DestroyParentHediff(Hediff parentHediff, bool debug = false)
+ {
+ if (parentHediff.pawn != null && parentHediff.def.defName != null && debug)
+ {
+ Warn(parentHediff.pawn.Label + "'s Hediff: " + parentHediff.def.defName + " says goodbye.", debug);
+ }
+ parentHediff.Severity = 0f;
+ }
+
+ private float GetPawnAgeOverlifeExpectancyRatio(Pawn pawn, bool debug = false)
+ {
+ float result = 1f;
+ if (pawn == null)
+ {
+ if (debug)
+ {
+ Warn("GetPawnAgeOverlifeExpectancyRatio pawn NOT OK", debug);
+ }
+ return result;
+ }
+ result = pawn.ageTracker.AgeBiologicalYearsFloat / pawn.RaceProps.lifeExpectancy;
+ if (debug)
+ {
+ Warn(string.Concat(new string[]
+ {
+ pawn.Label,
+ " Age: ",
+ pawn.ageTracker.AgeBiologicalYearsFloat.ToString(),
+ "; lifeExpectancy: ",
+ pawn.RaceProps.lifeExpectancy.ToString(),
+ "; ratio:",
+ result.ToString()
+ }), debug);
+ }
+ return result;
+ }
+
+ private bool OkPawn(Pawn pawn)
+ {
+ return pawn != null && pawn.Map != null;
+ }
+
+ private void Warn(string warning, bool debug = false)
+ {
+ if (debug)
+ {
+ Log.Message($"[HediffComp_Spawner] {warning}");
+ }
+ }
+
+ private int ticksUntilSpawn;
+ private int initialTicksUntilSpawn;
+ private int hungerReset;
+ private int healthReset;
+ private int graceTicks;
+ private Pawn pawn;
+ private float calculatedMaxDaysB4Next = 2f;
+ private float calculatedMinDaysB4Next = 1f;
+ private int calculatedQuantity = 1;
+ private bool blockSpawn;
+ private bool myDebug;
+ private readonly float errorMinDaysB4Next = 0.001f;
+ private readonly int errorExponentialLimit = 20;
+ private readonly int errorSpawnCount = 750;
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffCompProperties_Spawner.cs b/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffCompProperties_Spawner.cs
deleted file mode 100644
index 89d45d9..0000000
--- a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffCompProperties_Spawner.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using System;
-using Verse;
-
-namespace ArachnaeSwarm.MoharHediffs
-{
- public class HediffCompProperties_Spawner : HediffCompProperties
- {
- public HediffCompProperties_Spawner()
- {
- this.compClass = typeof(HediffComp_Spawner);
- }
-
- ///
- /// 要生成的物品的ThingDef。如果animalThing为false,则使用此项。
- ///
- public ThingDef thingToSpawn;
-
- ///
- /// 每次生成的基础物品数量。
- ///
- public int spawnCount = 1;
-
- ///
- /// 如果为true,则生成一个Pawn(动物)。如果为false,则生成一个Thing。
- ///
- public bool animalThing;
-
- ///
- /// 要生成的动物的PawnKindDef。如果animalThing为true,则使用此项。
- ///
- public PawnKindDef animalToSpawn;
-
- ///
- /// 如果为true,生成的动物将属于玩家派系。
- ///
- public bool factionOfPlayerAnimal;
-
- ///
- /// 下一次生成事件发生前的最少天数。
- ///
- public float minDaysB4Next = 1f;
-
- ///
- /// 下一次生成事件发生前的最大天数。
- ///
- public float maxDaysB4Next = 2f;
-
- ///
- /// 生成后进入宽限期(延迟下一次生成)的几率(0.0到1.0)。
- ///
- public float randomGrace;
-
- ///
- /// 如果触发,宽限期的持续时间(天)。
- ///
- public float graceDays = 0.5f;
-
- ///
- /// 附近允许的相同Pawn的最大数量。如果超过该数量,则暂停生成。-1为禁用。
- ///
- public int spawnMaxAdjacent = -1;
-
- ///
- /// 如果为true,生成的物品将被禁用。
- ///
- public bool spawnForbidden;
-
- ///
- /// 如果为true,当宿主Pawn饥饿时,生成将暂停。
- ///
- public bool hungerRelative;
-
- ///
- /// 如果为true,当宿主Pawn受伤时,生成将暂停。
- ///
- public bool healthRelative;
-
- ///
- /// 如果为true,生成数量将根据宿主的年龄进行调整。
- ///
- public bool ageWeightedQuantity;
-
- ///
- /// 如果为true,生成周期(两次生成之间的时间)将根据宿主的年龄进行调整。
- ///
- public bool ageWeightedPeriod;
-
- ///
- /// 如果为true且ageWeightedPeriod为true,则随着宿主年龄增长,生成周期变短。如果为false,则变长。
- ///
- public bool olderSmallerPeriod;
-
- ///
- /// 如果为true且ageWeightedQuantity为true,则随着宿主年龄增长,生成数量变多。如果为false,则变少。
- ///
- public bool olderBiggerQuantity;
-
- ///
- /// 如果为true且ageWeightedQuantity为true,则随年龄增长的数量缩放将是指数性的而非线性的。
- ///
- public bool exponentialQuantity;
-
- ///
- /// 指数级数量缩放的最大乘数,以防止出现荒谬的数字。
- ///
- public int exponentialRatioLimit = 15;
-
- ///
- /// 生成时显示的消息的翻译键(例如,“{PAWN}下了一个蛋。”)。
- ///
- public string spawnVerb = "delivery";
-
- ///
- /// 如果为true,则为此组件启用详细的调试日志记录。
- ///
- public bool debug;
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffComp_Spawner.cs b/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffComp_Spawner.cs
deleted file mode 100644
index a545cfe..0000000
--- a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/HediffComp_Spawner.cs
+++ /dev/null
@@ -1,739 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using RimWorld;
-using RimWorld.Planet;
-using Verse;
-
-namespace ArachnaeSwarm.MoharHediffs
-{
- public class HediffComp_Spawner : HediffComp
- {
- public HediffCompProperties_Spawner Props
- {
- get
- {
- return (HediffCompProperties_Spawner)this.props;
- }
- }
-
- public override void CompExposeData()
- {
- Scribe_Values.Look(ref this.ticksUntilSpawn, "ticksUntilSpawn", 0, false);
- Scribe_Values.Look(ref this.initialTicksUntilSpawn, "initialTicksUntilSpawn", 0, false);
- Scribe_Values.Look(ref this.calculatedMinDaysB4Next, "calculatedMinDaysB4Next", 0f, false);
- Scribe_Values.Look(ref this.calculatedMaxDaysB4Next, "calculatedMaxDaysB4Next", 0f, false);
- Scribe_Values.Look(ref this.calculatedQuantity, "calculatedQuantity", 0, false);
- Scribe_Values.Look(ref this.graceTicks, "graceTicks", 0, false);
- }
-
- public override void CompPostMake()
- {
- this.myDebug = this.Props.debug;
- Tools.Warn(string.Concat(new string[]
- {
- ">>> ",
- this.parent.pawn.Label,
- " - ",
- this.parent.def.defName,
- " - CompPostMake start"
- }), this.myDebug);
- this.TraceProps();
- this.CheckProps();
- this.CalculateValues();
- this.CheckCalculatedValues();
- this.TraceCalculatedValues();
- if (this.initialTicksUntilSpawn == 0)
- {
- Tools.Warn("Reseting countdown bc initialTicksUntilSpawn == 0 (comppostmake)", this.myDebug);
- this.ResetCountdown();
- }
- }
-
- public override void CompPostTick(ref float severityAdjustment)
- {
- this.pawn = this.parent.pawn;
- if (!Tools.OkPawn(this.pawn))
- {
- return;
- }
- if (this.blockSpawn)
- {
- return;
- }
- if (this.graceTicks > 0)
- {
- this.graceTicks--;
- return;
- }
- if (this.Props.hungerRelative && this.pawn.IsHungry(this.myDebug))
- {
- int num = (int)(this.RandomGraceDays() * 60000f);
- this.hungerReset++;
- this.graceTicks = num;
- return;
- }
- if (this.Props.healthRelative && this.pawn.IsInjured(this.myDebug))
- {
- int num2 = (int)(this.RandomGraceDays() * 60000f);
- this.healthReset++;
- this.graceTicks = num2;
- return;
- }
- this.hungerReset = (this.healthReset = 0);
- if (this.CheckShouldSpawn())
- {
- Tools.Warn("Reseting countdown bc spawned thing", this.myDebug);
- this.CalculateValues();
- this.CheckCalculatedValues();
- this.ResetCountdown();
- if (Rand.Chance(this.Props.randomGrace))
- {
- int num3 = (int)(this.RandomGraceDays() * 60000f);
- this.graceTicks = num3;
- }
- }
- }
-
- private void TraceProps()
- {
- Tools.Warn(string.Concat(new string[]
- {
- "Props => minDaysB4Next: ",
- this.Props.minDaysB4Next.ToString(),
- "; maxDaysB4Next: ",
- this.Props.maxDaysB4Next.ToString(),
- "; randomGrace: ",
- this.Props.randomGrace.ToString(),
- "; graceDays: ",
- this.Props.graceDays.ToString(),
- "; hungerRelative: ",
- this.Props.hungerRelative.ToString(),
- "; healthRelative: ",
- this.Props.healthRelative.ToString(),
- "; "
- }), this.myDebug);
- if (this.Props.animalThing)
- {
- Tools.Warn(string.Concat(new string[]
- {
- "animalThing: ",
- this.Props.animalThing.ToString(),
- "; animalName: ",
- this.Props.animalToSpawn.defName,
- "; factionOfPlayerAnimal: ",
- this.Props.factionOfPlayerAnimal.ToString(),
- "; "
- }), this.myDebug);
- }
- if (this.Props.ageWeightedQuantity)
- {
- Tools.Warn(string.Concat(new string[]
- {
- "ageWeightedQuantity:",
- this.Props.ageWeightedQuantity.ToString(),
- "; olderBiggerQuantity:",
- this.Props.olderBiggerQuantity.ToString(),
- "; ",
- this.myDebug.ToString()
- }), false);
- if (this.Props.exponentialQuantity)
- {
- Tools.Warn(string.Concat(new string[]
- {
- "exponentialQuantity:",
- this.Props.exponentialQuantity.ToString(),
- "; exponentialRatioLimit:",
- this.Props.exponentialRatioLimit.ToString(),
- "; "
- }), this.myDebug);
- }
- }
- Tools.Warn(string.Concat(new string[]
- {
- "ageWeightedPeriod:",
- this.Props.ageWeightedPeriod.ToString(),
- "; olderSmallerPeriod:",
- this.Props.olderSmallerPeriod.ToString(),
- "; ",
- this.myDebug.ToString()
- }), false);
- }
-
- private void CalculateValues()
- {
- float num = Tools.GetPawnAgeOverlifeExpectancyRatio(this.parent.pawn, this.myDebug);
- num = ((num > 1f) ? 1f : num);
- this.calculatedMinDaysB4Next = this.Props.minDaysB4Next;
- this.calculatedMaxDaysB4Next = this.Props.maxDaysB4Next;
- if (this.Props.ageWeightedPeriod)
- {
- float num2 = this.Props.olderSmallerPeriod ? (-num) : num;
- this.calculatedMinDaysB4Next = this.Props.minDaysB4Next * (1f + num2);
- this.calculatedMaxDaysB4Next = this.Props.maxDaysB4Next * (1f + num2);
- Tools.Warn(string.Concat(new string[]
- {
- " ageWeightedPeriod: ",
- this.Props.ageWeightedPeriod.ToString(),
- " ageRatio: ",
- num.ToString(),
- " minDaysB4Next: ",
- this.Props.minDaysB4Next.ToString(),
- " maxDaysB4Next: ",
- this.Props.maxDaysB4Next.ToString(),
- " daysAgeRatio: ",
- num2.ToString(),
- " calculatedMinDaysB4Next: ",
- this.calculatedMinDaysB4Next.ToString(),
- "; calculatedMaxDaysB4Next: ",
- this.calculatedMaxDaysB4Next.ToString(),
- "; "
- }), this.myDebug);
- }
- this.calculatedQuantity = this.Props.spawnCount;
- if (this.Props.ageWeightedQuantity)
- {
- float num3 = this.Props.olderBiggerQuantity ? num : (-num);
- Tools.Warn("quantityAgeRatio: " + num3.ToString(), this.myDebug);
- this.calculatedQuantity = (int)Math.Round((double)this.Props.spawnCount * (double)(1f + num3));
- if (this.Props.exponentialQuantity)
- {
- num3 = 1f - num;
- if (num3 == 0f)
- {
- Tools.Warn(">ERROR< quantityAgeRatio is f* up : " + num3.ToString(), this.myDebug);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- float num4 = this.Props.olderBiggerQuantity ? (1f / num3) : (num3 * num3);
- bool flag = false;
- bool flag2 = false;
- if (num4 > (float)this.Props.exponentialRatioLimit)
- {
- num4 = (float)this.Props.exponentialRatioLimit;
- flag = true;
- }
- this.calculatedQuantity = (int)Math.Round((double)this.Props.spawnCount * (double)num4);
- if (this.calculatedQuantity < 1)
- {
- this.calculatedQuantity = 1;
- flag2 = true;
- }
- Tools.Warn(string.Concat(new string[]
- {
- " exponentialQuantity: ",
- this.Props.exponentialQuantity.ToString(),
- "; expoFactor: ",
- num4.ToString(),
- "; gotLimited: ",
- flag.ToString(),
- "; gotAugmented: ",
- flag2.ToString()
- }), this.myDebug);
- }
- Tools.Warn("; Props.spawnCount: " + this.Props.spawnCount.ToString() + "; calculatedQuantity: " + this.calculatedQuantity.ToString(), this.myDebug);
- }
- }
-
- private void CheckCalculatedValues()
- {
- if (this.calculatedQuantity > this.errorSpawnCount)
- {
- Tools.Warn(string.Concat(new string[]
- {
- ">ERROR< calculatedQuantity is too high: ",
- this.calculatedQuantity.ToString(),
- "(>",
- this.errorSpawnCount.ToString(),
- "), check and adjust your hediff props"
- }), this.myDebug);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.calculatedMinDaysB4Next < this.errorMinDaysB4Next)
- {
- this.calculatedMinDaysB4Next = this.errorMinDaysB4Next;
- }
- if (this.calculatedMaxDaysB4Next < this.errorMinDaysB4Next)
- {
- this.calculatedMaxDaysB4Next = this.errorMinDaysB4Next;
- }
- }
-
- private void TraceCalculatedValues()
- {
- Tools.Warn("calculatedMinDaysB4Next:" + this.calculatedMinDaysB4Next.ToString(), this.myDebug);
- Tools.Warn("calculatedMaxDaysB4Next:" + this.calculatedMaxDaysB4Next.ToString(), this.myDebug);
- Tools.Warn("calculatedQuantity:" + this.calculatedQuantity.ToString(), this.myDebug);
- }
-
- private void CheckProps()
- {
- if (this.Props.animalThing && this.Props.animalToSpawn == null)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with animalflag but without animalToSpawn", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.Props.minDaysB4Next <= 0f)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative minDaysB4Next", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.Props.maxDaysB4Next <= 0f)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative maxDaysB4Next", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.Props.maxDaysB4Next < this.Props.minDaysB4Next)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with maxDaysB4Next < minDaysB4Next", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.Props.spawnCount <= 0)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner with null/negative spawnCount", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (!this.Props.animalThing && this.Props.thingToSpawn == null)
- {
- Tools.Warn(this.parent.pawn.Label + " has a hediffcomp_spawner without thingToSpawn", true);
- this.blockSpawn = true;
- Tools.DestroyParentHediff(this.parent, this.myDebug);
- return;
- }
- if (this.Props.ageWeightedQuantity && this.Props.exponentialQuantity && this.Props.exponentialRatioLimit > this.errorExponentialLimit)
- {
- Tools.Warn(string.Concat(new string[]
- {
- this.parent.pawn.Label,
- " has a hediffcomp_spawner with exponentialRatioLimit>",
- this.errorExponentialLimit.ToString(),
- " this is not allowed. It will be set to ",
- this.errorExponentialLimit.ToString()
- }), true);
- this.Props.exponentialRatioLimit = this.errorExponentialLimit;
- }
- }
-
- private bool CheckShouldSpawn()
- {
- this.ticksUntilSpawn--;
- if (this.ticksUntilSpawn <= 0)
- {
- if (this.TryDoSpawn())
- {
- return true;
- }
- Tools.Warn("Did not spawn, reseting countdown", this.myDebug);
- this.ResetCountdown();
- }
- return false;
- }
-
- private PawnKindDef MyPawnKindDefNamed(string myDefName)
- {
- return DefDatabase.GetNamed(myDefName, true);
- }
-
- public bool TryDoSpawn()
- {
- Pawn pawn = this.parent.pawn;
-
- if (this.Props.animalThing)
- {
- // 动物生成逻辑保持不变
- if (this.Props.spawnMaxAdjacent > 0 && pawn.Map.mapPawns.AllPawns.Where(delegate(Pawn mP)
- {
- ThingDef defToCompare = this.Props.animalThing ? this.Props.animalToSpawn?.race : this.Props.thingToSpawn;
- if (defToCompare?.race == null)
- {
- return false;
- }
- return mP.def == defToCompare && mP.Position.InHorDistOf(pawn.Position, (float)this.Props.spawnMaxAdjacent);
- }).Count() >= this.Props.spawnMaxAdjacent)
- {
- return false;
- }
-
- if (this.Props.animalToSpawn == null)
- {
- return false;
- }
-
- Faction faction = this.Props.factionOfPlayerAnimal ? Faction.OfPlayer : null;
- int i = 0;
- while (i < this.calculatedQuantity)
- {
- IntVec3 intVec;
- if (!this.TryFindSpawnCell(out intVec))
- {
- return false;
- }
- Pawn pawn2 = PawnGenerator.GeneratePawn(this.Props.animalToSpawn, faction);
- if (pawn2 == null)
- {
- return false;
- }
- GenSpawn.Spawn(pawn2, intVec, pawn.Map, WipeMode.Vanish);
- pawn2.SetFaction(faction, null);
- FilthMaker.TryMakeFilth(intVec, pawn.Map, ThingDefOf.Filth_AmnioticFluid, pawn.LabelIndefinite(), 5, FilthSourceFlags.None);
- if (!this.Props.spawnForbidden)
- {
- pawn2.playerSettings.Master = pawn;
- pawn2.training.Train(TrainableDefOf.Obedience, pawn, true);
- }
- i++;
- continue;
- }
- if (PawnUtility.ShouldSendNotificationAbout(pawn) || PawnUtility.ShouldSendNotificationAbout(pawn))
- {
- Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.PositiveEvent, true);
- }
- return true;
- }
- else
- {
- // 重新设计物品生成逻辑:按优先级顺序尝试
- return TrySpawnItemWithPriority(pawn);
- }
- }
-
- // 新增:按优先级顺序尝试生成物品
- private bool TrySpawnItemWithPriority(Pawn pawn)
- {
- Thing thing = ThingMaker.MakeThing(this.Props.thingToSpawn, null);
- if (thing == null)
- {
- Tools.Warn("Failed to create thing: " + this.Props.thingToSpawn?.defName, this.myDebug);
- return false;
- }
- thing.stackCount = this.calculatedQuantity;
-
- // 记录原始物品用于校验
- ThingDef originalThingDef = thing.def;
- int originalStackCount = thing.stackCount;
-
- // 按优先级顺序尝试生成
- bool success = false;
- string spawnMethod = "";
-
- // 优先级1: 尝试在pawn附近空地生成
- if (!success)
- {
- success = TrySpawnAtNearbyEmptyCell(pawn, thing, ref spawnMethod);
- }
-
- // 优先级2: 尝试在pawn脚底生成
- if (!success)
- {
- success = TrySpawnAtPawnPosition(pawn, thing, ref spawnMethod);
- }
-
- // 优先级3: 尝试放入pawn物品栏
- if (!success)
- {
- success = TrySpawnInInventory(pawn, thing, ref spawnMethod);
- }
-
- // 生成后校验
- if (success)
- {
- bool verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, spawnMethod);
-
- // 如果校验失败且不是在物品栏中生成的,尝试在物品栏中重新生成
- if (!verified && spawnMethod != "inventory")
- {
- Tools.Warn($"Spawn verification failed for {spawnMethod}, attempting inventory fallback", this.myDebug);
-
- // 重新创建物品
- Thing fallbackThing = ThingMaker.MakeThing(originalThingDef, null);
- fallbackThing.stackCount = originalStackCount;
-
- success = TrySpawnInInventory(pawn, fallbackThing, ref spawnMethod);
-
- if (success)
- {
- verified = VerifySpawnSuccess(pawn, originalThingDef, originalStackCount, "inventory_fallback");
- if (!verified)
- {
- Tools.Warn("Inventory fallback also failed verification", this.myDebug);
- success = false;
- }
- }
- }
-
- if (success && verified)
- {
- if (PawnUtility.ShouldSendNotificationAbout(pawn))
- {
- Messages.Message(this.Props.spawnVerb.Translate(pawn.Named("PAWN"), thing.Named("THING")),
- spawnMethod == "inventory" || spawnMethod == "inventory_fallback" ? pawn : thing,
- MessageTypeDefOf.PositiveEvent, true);
- }
- Tools.Warn($"Successfully spawned {originalStackCount}x {originalThingDef.defName} via {spawnMethod}", this.myDebug);
- return true;
- }
- }
-
- Tools.Warn($"Failed to spawn {originalStackCount}x {originalThingDef.defName} after all attempts", this.myDebug);
- return false;
- }
-
- // 新增:尝试在附近空地生成
- private bool TrySpawnAtNearbyEmptyCell(Pawn pawn, Thing thing, ref string spawnMethod)
- {
- IntVec3 spawnCell;
- if (TryFindSpawnCell(out spawnCell))
- {
- if (this.Props.spawnForbidden)
- {
- thing.SetForbidden(true, true);
- }
-
- if (GenPlace.TryPlaceThing(thing, spawnCell, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4)))
- {
- spawnMethod = "nearby_cell";
- return true;
- }
- }
- return false;
- }
-
- // 新增:尝试在pawn位置生成
- private bool TrySpawnAtPawnPosition(Pawn pawn, Thing thing, ref string spawnMethod)
- {
- IntVec3 pawnPosition = pawn.Position;
- if (pawnPosition.IsValid && pawnPosition.Walkable(pawn.Map))
- {
- if (this.Props.spawnForbidden)
- {
- thing.SetForbidden(true, true);
- }
-
- if (GenPlace.TryPlaceThing(thing, pawnPosition, pawn.Map, ThingPlaceMode.Direct, null, null, default(Rot4)))
- {
- spawnMethod = "pawn_position";
- return true;
- }
- }
- return false;
- }
-
- // 新增:尝试在物品栏生成
- private bool TrySpawnInInventory(Pawn pawn, Thing thing, ref string spawnMethod)
- {
- if (pawn.inventory == null)
- {
- Tools.Warn($"Pawn {pawn.Label} does not have an inventory", this.myDebug);
- return false;
- }
-
- if (pawn.inventory.innerContainer.TryAdd(thing))
- {
- spawnMethod = "inventory";
- return true;
- }
- return false;
- }
-
- // 新增:生成后校验
- private bool VerifySpawnSuccess(Pawn pawn, ThingDef thingDef, int expectedCount, string spawnMethod)
- {
- bool verificationSuccess = false;
-
- switch (spawnMethod)
- {
- case "nearby_cell":
- case "pawn_position":
- case "inventory_fallback":
- // 检查地图上是否有生成的物品
- verificationSuccess = pawn.Map.listerThings.ThingsOfDef(thingDef)
- .Any(t => t.stackCount >= expectedCount && t.Position.InHorDistOf(pawn.Position, 2f));
- break;
-
- case "inventory":
- // 检查物品栏中是否有生成的物品
- verificationSuccess = pawn.inventory.innerContainer.Any(t => t.def == thingDef && t.stackCount >= expectedCount);
- break;
- }
-
- if (!verificationSuccess)
- {
- Tools.Warn($"Spawn verification failed for {thingDef.defName} via {spawnMethod}", this.myDebug);
- }
- else
- {
- Tools.Warn($"Spawn verification successful for {thingDef.defName} via {spawnMethod}", this.myDebug);
- }
-
- return verificationSuccess;
- }
-
- private bool TryFindSpawnCell(out IntVec3 result)
- {
- result = IntVec3.Invalid;
- bool result2;
- if (this.pawn == null)
- {
- result2 = false;
- }
- else
- {
- Map map = this.pawn.Map;
- if (map == null)
- {
- result2 = false;
- }
- else
- {
- // 修改这里:将半径从5减少到2,让生成位置更靠近pawn
- int searchRadius = 2;
-
- // 首先尝试在pawn的相邻单元格生成(半径为1)
- result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, 1, null);
-
- // 如果相邻单元格找不到合适位置,再尝试稍远一点(半径为2)
- if (!result.IsValid)
- {
- result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, searchRadius, null);
- }
-
- // 如果还是找不到,尝试pawn当前位置(作为最后手段)
- if (!result.IsValid && this.pawn.Position.IsValid && this.pawn.Position.Walkable(map))
- {
- result = this.pawn.Position;
- }
-
- result2 = result.IsValid;
- }
- }
- return result2;
- }
-
-
- private void ResetCountdown()
- {
- this.ticksUntilSpawn = (int)(this.RandomDays2wait() * 60000f);
- this.initialTicksUntilSpawn = this.ticksUntilSpawn;
- }
-
- private float RandomDays2wait()
- {
- return Rand.Range(this.calculatedMinDaysB4Next, this.calculatedMaxDaysB4Next);
- }
-
- private float RandomGraceDays()
- {
- return Rand.Range(this.Props.graceDays / 2f, this.Props.graceDays);
- }
-
- public override string CompTipStringExtra
- {
- get
- {
- if (!this.myDebug)
- {
- return null;
- }
- string text = "ticksUntilSpawn: " + this.ticksUntilSpawn.ToString() + "\n";
- string text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "initialTicksUntilSpawn: ",
- this.initialTicksUntilSpawn.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "graceTicks: ",
- this.graceTicks.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "hunger resets: ",
- this.hungerReset.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "health resets: ",
- this.healthReset.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "calculatedMinDaysB4Next: ",
- this.calculatedMinDaysB4Next.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "calculatedMaxDaysB4Next: ",
- this.calculatedMaxDaysB4Next.ToString(),
- "\n"
- });
- text2 = text;
- text = string.Concat(new string[]
- {
- text2,
- "calculatedQuantity: ",
- this.calculatedQuantity.ToString(),
- "\n"
- });
- return text + "blockSpawn: " + this.blockSpawn.ToString();
- }
- }
-
- private int ticksUntilSpawn;
-
- private int initialTicksUntilSpawn;
-
- private int hungerReset;
-
- private int healthReset;
-
- private int graceTicks;
-
- private Pawn pawn;
-
- private float calculatedMaxDaysB4Next = 2f;
-
- private float calculatedMinDaysB4Next = 1f;
-
- private int calculatedQuantity = 1;
-
- private bool blockSpawn;
-
- private bool myDebug;
-
- private readonly float errorMinDaysB4Next = 0.001f;
-
- private readonly int errorExponentialLimit = 20;
-
- private readonly int errorSpawnCount = 750;
- }
-}
diff --git a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/Tools.cs b/Source/ArachnaeSwarm/Hediffs/MoharHediffs/Tools.cs
deleted file mode 100644
index 21a78e7..0000000
--- a/Source/ArachnaeSwarm/Hediffs/MoharHediffs/Tools.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-using System.Collections.Generic;
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace ArachnaeSwarm.MoharHediffs
-{
- public static class Tools
- {
- public static void DestroyParentHediff(Hediff parentHediff, bool debug = false)
- {
- if (parentHediff.pawn != null && parentHediff.def.defName != null && debug)
- {
- ArachnaeLog.Debug(parentHediff.pawn.Label + "'s Hediff: " + parentHediff.def.defName + " says goodbye.");
- }
- parentHediff.Severity = 0f;
- }
-
- public static float GetPawnAgeOverlifeExpectancyRatio(Pawn pawn, bool debug = false)
- {
- float result = 1f;
- if (pawn == null)
- {
- if (debug)
- {
- ArachnaeLog.Debug("GetPawnAgeOverlifeExpectancyRatio pawn NOT OK");
- }
- return result;
- }
- result = pawn.ageTracker.AgeBiologicalYearsFloat / pawn.RaceProps.lifeExpectancy;
- if (debug)
- {
- ArachnaeLog.Debug(string.Concat(new string[]
- {
- pawn.Label,
- " Age: ",
- pawn.ageTracker.AgeBiologicalYearsFloat.ToString(),
- "; lifeExpectancy: ",
- pawn.RaceProps.lifeExpectancy.ToString(),
- "; ratio:",
- result.ToString()
- }));
- }
- return result;
- }
-
- public static bool IsInjured(this Pawn pawn, bool debug = false)
- {
- if (pawn == null)
- {
- if (debug)
- {
- ArachnaeLog.Debug("pawn is null - wounded ");
- }
- return false;
- }
- float num = 0f;
- List hediffs = pawn.health.hediffSet.hediffs;
- for (int i = 0; i < hediffs.Count; i++)
- {
- if (hediffs[i] is Hediff_Injury && !hediffs[i].IsPermanent())
- {
- num += hediffs[i].Severity;
- }
- }
- if (debug && num > 0f)
- {
- ArachnaeLog.Debug(pawn.Label + " is wounded ");
- }
- return num > 0f;
- }
-
- public static bool IsHungry(this Pawn pawn, bool debug = false)
- {
- if (pawn == null)
- {
- if (debug)
- {
- ArachnaeLog.Debug("pawn is null - IsHungry ");
- }
- return false;
- }
- bool flag = pawn.needs.food != null && pawn.needs.food.CurCategory == HungerCategory.Starving;
- if (debug && flag)
- {
- ArachnaeLog.Debug(pawn.Label + " is hungry ");
- }
- return flag;
- }
-
- public static bool OkPawn(Pawn pawn)
- {
- return pawn != null && pawn.Map != null;
- }
-
- public static void Warn(string warning, bool debug = false)
- {
- if (debug)
- {
- ArachnaeLog.Debug(warning);
- }
- }
-
- }
-}
\ No newline at end of file