diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 42ca4fd..dca9f11 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 42bc198..bcde82f 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -1578,10 +1578,36 @@
+
+ ARA_Locust_Needle_Fire
+ 毒针连射
+ 阿拉克涅督虫使用可以喷射剧毒尾针的毒针腺对敌方进行一轮射击。
+ True
+ False
+ 120
+ true
+ ArachnaeSwarm/UI/Abilities/ARA_Toxic_Needle_Fire
+
+ Verb_CastAbility
+ 24
+ 1
+ Heatspikes_Shot
+ Heatspikes_Tail
+
+ True
+
+
+
+
+ Bullet_ARA_RW_Basic_Fist_Needle_Gun
+ 12
+
+
+
- ARA_Pouch_Hatching_Acidling
+ ARA_Pouch_Hatching_Baneling
蜕荚孵化:爆裂种
立刻在脚下孵化三只阿拉克涅爆裂种辅虫,它们会对敌方发起自杀性攻击。
ArachnaeSwarm/UI/Abilities/ARA_BaseRace_Launcher
@@ -1603,7 +1629,7 @@
- ArachnaeBase_Race_Acidling_Proj
+ ArachnaeBase_Race_Baneling_Proj
3
diff --git a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
index 7f3ba69..0e2a17a 100644
--- a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
+++ b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
@@ -1260,7 +1260,7 @@
ARA_Skyraider_Hivelord
空天种转换——巢虫之主
- 使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得向敌方自动投射天巢种辅虫的能力——这种辅虫体型很小,会以让人烦扰的近战紧紧黏住敌人。\n\n该进化过程不可逆!
+ 使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得孵化大量天巢种辅虫的能力——这种辅虫体型很小,会以让人烦扰的近战紧紧黏住敌人。\n\n该进化方向提供8只阿拉克涅天巢种辅虫。
ArachnaeSwarm/UI/Abilities/ARA_Skyraider_Hivelord
1800
false
@@ -1299,7 +1299,7 @@
ARA_Skyraider_Hivelord
亚种-领主种
- 这只阿拉克涅空天种已经获得拔耀,会对敌方投掷天巢种辅虫,这些灵敏的辅虫会在落地后散开四处狩猎目标。
+ 这只阿拉克涅空天种已经获得拔耀,可以孵化大量的天巢种辅虫,这些灵敏的辅虫会后散开四处狩猎目标。
HediffWithComps
(0.6, 0.4, 0.8)
false
@@ -1343,15 +1343,24 @@
-
+
+
+
+ ArachnaeBase_Race_Skyhive
+ 8
+ 400
+
+
+
+
+ ARA_Mote_Hivelord_Turret_Range
true
-
+ -->
@@ -1374,7 +1383,7 @@
ARA_Skyraider_Empthrower
空天种转换——电磁风暴
- 使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得向敌方自动投射磁暴种辅虫的能力——这种辅虫会以自杀式袭击的方式释放出EMP,以对抗机械族。\n\n该进化过程不可逆!
+ 使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得孵化磁暴种辅虫的能力——这种辅虫会以自杀式袭击的方式释放出EMP,以对抗机械族。\n\n该进化方向提供3只阿拉克涅电磁种辅虫。
ArachnaeSwarm/UI/Abilities/ARA_Skyraider_Empthrower
1800
false
@@ -1413,7 +1422,7 @@
ARA_Skyraider_Empthrower
亚种-飓风种
- 这只阿拉克涅空天种已经获得拔耀,会对敌方投掷磁暴种辅虫,这些辅虫会在落地后散开,以自杀性袭击释放EMP对抗敌方机械族。
+ 这只阿拉克涅空天种已经获得拔耀,会孵化磁暴种辅虫,这些辅虫以自杀性袭击释放EMP对抗敌方机械族。
HediffWithComps
(0.6, 0.4, 0.8)
false
@@ -1457,7 +1466,16 @@
-
+
+
+
+ ArachnaeBase_Race_Empsuicider
+ 3
+ 500
+
+
+
+
@@ -1508,10 +1526,19 @@
-
- ARA_Praetorian_Base_Turret
- 0
- true
+
+
+
+ ArachnaeBase_Race_Acidcut
+ 3
+ 500
+
+
+ ArachnaeBase_Race_Locust
+ 2
+ 700
+
+
@@ -1531,7 +1558,7 @@
ARA_Praetorian_Navigator
禁卫种转换——引航灯塔
- 使禁卫种发生内驱性进化,以牺牲射击能力、跳跃能力、指挥能力为代价,使其换取指挥空中兽虫的能力。\n\n该进化过程不可逆!另外,空中兽虫必须成功升空才能进行指挥——在你解锁这个进化路径时,应该还不能建造空中兽虫。
+ 使禁卫种发生内驱性进化,以牺牲射击能力、跳跃能力、指挥能力为代价,使其换取指挥空中兽虫的能力。\n\n该进化方向不提供阿拉克涅辅虫。另外,空中兽虫必须成功升空才能进行指挥——在你解锁这个进化路径时,应该还不能建造空中兽虫。
ArachnaeSwarm/UI/Abilities/ARA_Praetorian_Navigator
1800
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 e67de4d..5b0078f 100644
--- a/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml
+++ b/1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Psy.xml
@@ -150,7 +150,7 @@
ArachnaeNode_Race_Skyraider
ArachnaeNode_Race_Praetorian
ArachnaeBase_Race_Acidcut
- ArachnaeBase_Race_Acidling
+ ArachnaeBase_Race_Baneling
ArachnaeBase_Race_Skyhive
ArachnaeNode_Race_MimicNematode
diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml
index 4da12c2..33b2cbd 100644
--- a/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml
+++ b/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml
@@ -284,8 +284,8 @@
0
0
-
- ArachnaeBase_Race_Acidling_Enermy
+
+ ArachnaeBase_Race_Baneling_Enermy
150
0
0
diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
index 167075a..c9c8487 100644
--- a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
+++ b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml
@@ -537,7 +537,7 @@
- ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin
+ ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin
1
(0.4, 0.5, 0.37)
@@ -606,15 +606,14 @@
-
-
- ArachnaeBase_Race_Acidling
+
+ ArachnaeBase_Race_Baneling
阿拉克涅爆裂种
- ArachnaeBase_Race_Acidling
+ ArachnaeBase_Race_Baneling
- ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin
+ ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin
1
(0.4, 0.5, 0.37)
@@ -635,7 +634,7 @@
- ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin
+ ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin
1
(0.4, 0.5, 0.37)
@@ -649,6 +648,30 @@
+
+ ArachnaeBase_Race_Locust
+ 阿拉克涅爆裂种
+ ArachnaeBase_Race_Locust
+
+
+
+ ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin
+ 1
+
+ (0.4, 0.5, 0.37)
+ (0,0,-0.15)
+
+
+
+ Things/Pawn/Animal/Spelopede/Dessicated_Spelopede
+ 1
+
+
+
+
+ ARA_Locust_Needle_Fire
+
+
ArachnaeBeast_Race_Slayer
diff --git a/1.6/1.6/Defs/RecipeDefs/ARA_Recipes.xml b/1.6/1.6/Defs/RecipeDefs/ARA_Recipes.xml
index e07e824..7f88436 100644
--- a/1.6/1.6/Defs/RecipeDefs/ARA_Recipes.xml
+++ b/1.6/1.6/Defs/RecipeDefs/ARA_Recipes.xml
@@ -700,11 +700,11 @@
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
爆裂种蜕荚
诱发阿拉克涅虫族的定向变异,使其蜕荚中预先储存三只即将孵化的阿拉克涅爆裂种,它们一旦被释放就会以自杀式袭击攻击敌方。
- ARA_Acidling_Pouch_Hediff
+ ARA_Baneling_Pouch_Hediff
正在实施定向变异
@@ -725,16 +725,16 @@
ARA_Activated_Bacterium
- ARA_Acidling_Pouch_Hediff
+ ARA_Baneling_Pouch_Hediff
ARA_Technology_4EVO
- ARA_Acidling_Pouch_Hediff
+ ARA_Baneling_Pouch_Hediff
爆裂种蜕荚
Hediff_Implant
阿拉克涅虫族的蜕荚里装了若干只即将孵化的阿拉克涅爆裂种,只需要获得指令就会立刻破体而出攻击敌方。
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
true
@@ -742,17 +742,17 @@
- ARA_Pouch_Hatching_Acidling
+ ARA_Pouch_Hatching_Baneling
- ARA_Acidling_Pouch
+ ARA_Baneling_Pouch
爆裂种蜕荚
阿拉克涅虫族的蜕荚里装了若干只即将孵化的阿拉克涅爆裂种,只需要获得指令就会立刻破体而出攻击敌方。该手术不需要制作部件,可以直接在阿拉克涅督虫身上实施。
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
ARA_Technology_4EVO
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
index 229ced0..e1afbb2 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
@@ -29,7 +29,7 @@
ARA_Surgery_Install_Reactive_Shell
ARA_Surgery_Install_Strengthening_Tendon
ARA_Surgery_Install_Slide_Patagium
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
ARA_Surgery_Install_Tumor_Pouch
ARA_Surgery_Install_Internal_Circulation_Lung
@@ -524,6 +524,74 @@
+
+ ArachnaeBase_Race_Empsuicider
+ 阿拉克涅电磁种
+ 阿拉克涅辅虫之一,智力低下,一般以自杀式袭击的方式伤害敌军,靠近敌人后就会释放EMP瘫痪附加的机械族,如果其监管者督虫处于征召状态,则会跟随督虫一起行动。
+
+ ARA_Insect_Baneling_Thinktree
+ 0.35
+
+ BeetleLikeWithClaw
+
+ DeathActionWorker_Vanish
+ Filth_Slime
+ 1~3
+
+
+
+ 6.6
+
+
+
+
+
+ Obedience
+ true
+ true
+
+
+ Release
+ true
+ true
+
+
+ Rescue
+ true
+ true
+
+
+ Tameness
+ true
+ true
+
+
+ AttackTarget
+ true
+ true
+
+
+ true
+
+
+ 6
+ EMP
+ 65
+ 2
+ Explosion_EMP
+
+
+
+
+ ARA_HiveMindWorker
+
+ 1.0
+ false
+
+
+
ArachnaeBase_Race_Skyhive
阿拉克涅天巢种
@@ -608,6 +676,80 @@
+
+ ArachnaeBase_Race_Locust
+ 阿拉克涅天巢种
+ 阿拉克涅辅虫之一,拥有贴地飞行的能力,无论是攻击还是移动速度非常快。
+
+ ARA_Insect_Locust_Thinktree
+ 0.36
+
+ BeetleLikeWithClaw
+
+ DeathActionWorker_Vanish
+ Filth_Slime
+ 1~3
+
+
+
+ 5.5
+
+ 0.4
+ 0.4
+ 0.25
+
+
+
+ 复合颚
+
+ Cut
+
+ 3
+ 0.8
+ HeadAttackTool
+ true
+
+
+
+
+
+
+ Obedience
+ true
+ true
+
+
+ Release
+ true
+ true
+
+
+ Rescue
+ true
+ true
+
+
+ Tameness
+ true
+ true
+
+
+ AttackTarget
+ true
+ true
+
+
+ true
+
+
+
+ ARA_HiveMindWorker
+
+ 1.0
+ false
+
+
+
ARA_AcidCut
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceDroneSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceDroneSwarm.xml
index 32f77bb..18cf944 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceDroneSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceDroneSwarm.xml
@@ -74,7 +74,7 @@
- ArachnaeBase_Race_Acidling
+ ArachnaeBase_Race_Baneling
阿拉克涅爆裂种
阿拉克涅辅虫之一,智力低下,一般以自杀式袭击的方式伤害敌军,靠近敌人后就会引爆酸囊产生危险的酸性雾气。
@@ -112,32 +112,5 @@
-
- ArachnaeBase_Race_Empsuicider
- 阿拉克涅爆裂种
- 阿拉克涅辅虫之一,智力低下,一般以自杀式袭击的方式伤害敌军,靠近敌人后就会释放EMP瘫痪附加的机械族。
-
- HunterDroneConstant
- 0.25
-
- BeetleLikeWithClaw
- 1
-
-
- 6
-
-
-
- 6
- EMP
- 65
- 2
- Explosion_EMP
-
-
-
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
index 49891e8..a54e4b7 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceNodeSwarm.xml
@@ -625,7 +625,7 @@
ARA_Surgery_Install_Reactive_Shell
ARA_Surgery_Install_Strengthening_Tendon
ARA_Surgery_Install_Slide_Patagium
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
ARA_Surgery_Install_Tumor_Pouch
ARA_Surgery_Install_Internal_Circulation_Lung
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 c12edb7..f057a0f 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml
@@ -556,7 +556,7 @@
ARA_Surgery_Install_Reactive_Shell
ARA_Surgery_Install_Strengthening_Tendon
ARA_Surgery_Install_Slide_Patagium
- ARA_Surgery_Install_Acidling_Pouch
+ ARA_Surgery_Install_Baneling_Pouch
ARA_Surgery_Install_Tumor_Pouch
ARA_Surgery_Install_Internal_Circulation_Lung
diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
index 08ec31c..354c788 100644
--- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
+++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml
@@ -2158,7 +2158,7 @@
阿拉克涅磁暴种
Projectile_SpawnsPawnZeroAge
- ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_north
+ ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_north
Graphic_Single
diff --git a/1.6/1.6/Defs/Thing_Plant/ARA_Plant.xml b/1.6/1.6/Defs/Thing_Plant/ARA_Plant.xml
index f2fca4c..ef045f3 100644
--- a/1.6/1.6/Defs/Thing_Plant/ARA_Plant.xml
+++ b/1.6/1.6/Defs/Thing_Plant/ARA_Plant.xml
@@ -96,7 +96,7 @@
- ARA_AcidlingTrapPlant
+ ARA_BanelingTrapPlant
爆裂巢花
ArachnaeSwarm.Plant_Transforming
一种由阿拉克涅虫群培育的真菌混合体,它会汲取菌毯的营养,在生长到一定阶段后进行变态发育,最终转换成一枚阿拉克涅爆裂茧——一种会对附近的敌军释放自杀性辅虫的特殊陷阱。
@@ -107,7 +107,7 @@
0.2
- ArachnaeSwarm/Plant/ARA_AcidlingTrapPlant
+ ArachnaeSwarm/Plant/ARA_BanelingTrapPlant
Graphic_Single
true
@@ -132,7 +132,7 @@
- Arachnae_AcidlingTrap
+ Arachnae_BanelingTrap
0.8
diff --git a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
index 46001d9..43ff5de 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
@@ -57,7 +57,7 @@
ARA_MorphableResearchBench
ARANutrientDispenser
ARA_WormholePortal_A
- ARA_Acidling_AutoMortar
+ ARA_Baneling_AutoMortar
CatastropheMissileSilo
ARA_AutoSniperCannon
ARA_Pawn_Ootheca
diff --git a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
index 584e597..4078a6d 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
@@ -198,7 +198,7 @@
- Arachnae_AcidlingTrap
+ Arachnae_BanelingTrap
阿拉克涅爆裂茧
一种阿拉克涅休眠茧,内藏有休眠中的阿拉克涅虫族。如果靠太近则会唤醒其中的虫族。
ArachnaeSwarm.Building_TrapReleaseRandom
@@ -228,7 +228,7 @@
50
- ArachnaeSwarm/Plant/ARA_AcidlingTrapPlant
+ ArachnaeSwarm/Plant/ARA_BanelingTrapPlant
Graphic_Single
1.2
@@ -242,7 +242,7 @@
5
3
- ArachnaeBase_Race_Acidling
+ ArachnaeBase_Race_Baneling
@@ -394,14 +394,14 @@
- ARA_Acidling_AutoMortar
+ ARA_Baneling_AutoMortar
爆裂种投射巢组织
阿拉克涅虫族用于防御巢穴的组织之一。它由大量没有自主意识的高度特化器官共同构成,能向进犯巢穴的敌军发射多只阿拉克涅爆裂种辅虫,这些辅虫将自行寻找目标以发起自杀性袭击。作为阿拉克涅防御组织,其可以通过获取营养来自行生成补充弹药。
ArachnaeSwarm.Building_TurretGunHasSpeed
MapMeshAndRealTime
true
true
- ArachnaeSwarm/Building/ARA_Acidling_AutoMortar_Icon
+ ArachnaeSwarm/Building/ARA_Baneling_AutoMortar_Icon
ArachnaeSwarm/Building/ARA_AutoSniperCannon_Base
Graphic_Single
@@ -481,7 +481,7 @@
Artillery
- ARA_Acidling_Artillery_AutoMortar
+ ARA_Baneling_Artillery_AutoMortar
10.0
3.0
@@ -496,10 +496,10 @@
8
- ARA_Acidling_Artillery_AutoMortar
+ ARA_Baneling_Artillery_AutoMortar
爆裂种投射巢
- ArachnaeSwarm/Building/ARA_Acidling_Artillery_AutoMortar_Tower
+ ArachnaeSwarm/Building/ARA_Baneling_Artillery_AutoMortar_Tower
Graphic_Single
1.25
@@ -509,7 +509,7 @@
ArachnaeSwarm.Verb_ShootWithOffset
- ArachnaeBase_Race_Acidling_Proj
+ ArachnaeBase_Race_Baneling_Proj
3
2
500
@@ -534,16 +534,16 @@
- ArachnaeBase_Race_Acidling_Proj
+ ArachnaeBase_Race_Baneling_Proj
阿拉克涅爆裂种
Projectile_SpawnsPawnZeroAge
- ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin
+ ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin
Graphic_Multi
41
- ArachnaeBase_Race_Acidling
+ ArachnaeBase_Race_Baneling
true
ARA_AcidBurn
10
diff --git a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
index 0bfca22..d66ff48 100644
--- a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
+++ b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
@@ -1102,6 +1102,26 @@
+
+
+
+
+
+
+ 100
+ 100
+
+
+
+
+
+ true
+
+
+
+
+
+
@@ -1442,6 +1462,26 @@
+
+
+
+
+
+
+ 100
+ 100
+
+
+
+
+
+ true
+
+
+
+
+
+
@@ -2305,6 +2345,26 @@
+
+
+
+
+
+
+ 100
+ 100
+
+
+
+
+
+ true
+
+
+
+
+
+
@@ -2559,6 +2619,26 @@
+
+
+
+
+
+
+ 100
+ 100
+
+
+
+
+
+ true
+
+
+
+
+
+
@@ -2691,6 +2771,313 @@
+
+ ARA_Insect_Locust_Thinktree
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+ Downed
+
+
+ BurningResponse
+
+
+ MentalStateCritical
+
+
+
+
+ 2.9
+
+
+
+
+
+
+
+ MentalStateNonCritical
+
+
+
+
+
+
+ Misc
+
+
+
+
+
+
+
+
+
+ RopedPawn
+
+
+
+
+ LordDuty
+
+
+
+ true
+
+
+
+ 30
+ 35
+
+
+
+
+ LeaveIfWrongSeason
+
+
+ LeaveIfStarving
+
+
+
+
+ 60
+
+
+ Misc
+
+
+ Walk
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ 60
+
+
+ Misc
+
+
+ Walk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.9~7.9
+ 13.5~20
+
+
+
+ 2.9
+
+
+
+ 65
+ 72
+ true
+ ARA_Locust_Needle_Fire
+ true
+ true
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.9~7.9
+ 13.5~20
+
+
+
+ 2.9
+
+
+
+ 65
+ 72
+ true
+ ARA_Locust_Needle_Fire
+ true
+ true
+
+
+
+
+
+
+
+
+
+ RestingForMedicalReasons
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SatisfyBasicNeeds
+
+
+
+
+
+
+ Idle
+
+
+
+
+
+ None
+ 160~300
+
+
+
+
+
+
+
+ None
+ 160~300
+ 1200
+
+
+
+
+ 0.1
+
+
+ None
+ 160~300
+ 1200
+
+
+
+
+
+ None
+ 160~300
+
+
+
+
+
+
+ None
+ 160~300
+
+
+
+
+
+
+
+
+
+
+ RestingForMedicalReasons
+
+
+
+
+
+
+ Misc
+
+
+ Walk
+
+
+
+
+
+
+
+
+ Idle
+
+
+
+
+ Deadly
+ 160~300
+
+
+
+
+
+ Deadly
+ 160~300
+
+
+
+
+
+
+
+
ARA_Humanlike
diff --git a/Content/Textures/ArachnaeSwarm/Building/ARA_Acidling_Artillery_AutoMortar_Tower.png b/Content/Textures/ArachnaeSwarm/Building/ARA_Baneling_Artillery_AutoMortar_Tower.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Building/ARA_Acidling_Artillery_AutoMortar_Tower.png
rename to Content/Textures/ArachnaeSwarm/Building/ARA_Baneling_Artillery_AutoMortar_Tower.png
diff --git a/Content/Textures/ArachnaeSwarm/Building/ARA_Acidling_AutoMortar_Icon.png b/Content/Textures/ArachnaeSwarm/Building/ARA_Baneling_AutoMortar_Icon.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Building/ARA_Acidling_AutoMortar_Icon.png
rename to Content/Textures/ArachnaeSwarm/Building/ARA_Baneling_AutoMortar_Icon.png
diff --git a/Content/Textures/ArachnaeSwarm/Plant/ARA_AcidlingTrapPlant.png b/Content/Textures/ArachnaeSwarm/Plant/ARA_BanelingTrapPlant.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Plant/ARA_AcidlingTrapPlant.png
rename to Content/Textures/ArachnaeSwarm/Plant/ARA_BanelingTrapPlant.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_east.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_east.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_east.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_east.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_north.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_north.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_north.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_north.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_south.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_south.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin_south.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/Bodies/Naked_Thin_south.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_east.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_east.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_east.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_east.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_north.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_north.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_north.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_north.png
diff --git a/Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_south.png b/Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_south.png
similarity index 100%
rename from Content/Textures/ArachnaeSwarm/Things/ARA_Acidling/BodiesEmp/Naked_Thin_south.png
rename to Content/Textures/ArachnaeSwarm/Things/ARA_Baneling/BodiesEmp/Naked_Thin_south.png
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 053f1e9..c1923e1 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 a5fb7ad..dafd83a 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -1,21 +1,41 @@
{
"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\\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\\buildings\\building_corpsevat\\building_corpsevat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_corpsevat\\building_corpsevat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_corpsevat\\jobdriver_haulcorpsetovat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_corpsevat\\jobdriver_haulcorpsetovat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_dormancyvat\\building_dormancyvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_dormancyvat\\building_dormancyvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_corpsevat\\corpsevatextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_corpsevat\\corpsevatextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_followproducer\\thinknode_conditionalnotproducedbymechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_followproducer\\thinknode_conditionalnotproducedbymechcarrier.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_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|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\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\\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|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\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_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|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\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_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}"
}
],
@@ -26,19 +46,84 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 1,
+ "SelectedChildIndex": 2,
"Children": [
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "CorpseVatExtension.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
+ "RelativeToolTip": "Buildings\\Building_CorpseVat\\CorpseVatExtension.cs",
+ "ViewState": "AgIAAAYAAAAAAAAAAAAAABkAAAAIAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-23T04:01:21.774Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "JobDriver_HaulCorpseToVat.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\JobDriver_HaulCorpseToVat.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_CorpseVat\\JobDriver_HaulCorpseToVat.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\JobDriver_HaulCorpseToVat.cs",
+ "RelativeToolTip": "Buildings\\Building_CorpseVat\\JobDriver_HaulCorpseToVat.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAA0AAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-23T04:01:20.292Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 0,
+ "Title": "Building_CorpseVat.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
+ "RelativeToolTip": "Buildings\\Building_CorpseVat\\Building_CorpseVat.cs",
+ "ViewState": "AgIAAEYBAAAAAAAAAAAawFgBAAAMAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-23T04:01:18.535Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
+ "Title": "Building_DormancyVat.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_DormancyVat\\Building_DormancyVat.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_DormancyVat\\Building_DormancyVat.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_DormancyVat\\Building_DormancyVat.cs",
+ "RelativeToolTip": "Buildings\\Building_DormancyVat\\Building_DormancyVat.cs",
+ "ViewState": "AgIAACUAAAAAAAAAAIA8wDcAAAAAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-23T03:49:32.234Z",
+ "EditorCaption": ""
+ },
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
- "DocumentIndex": 0,
+ "DocumentIndex": 4,
+ "Title": "ThinkNode_ConditionalNotProducedByMechCarrier.cs",
+ "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
+ "RelativeDocumentMoniker": "Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
+ "RelativeToolTip": "Jobs\\JobDriver_FollowProducer\\ThinkNode_ConditionalNotProducedByMechCarrier.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAA+AAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-23T02:44:35.619Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 5,
"Title": "Pawn_FlightTrackerPatches.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs",
+ "DocumentMoniker": "D:\\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",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_Flight\\Pawn_FlightTrackerPatches.cs",
"ViewState": "AgIAAB0AAAAAAAAAAAAuwEsAAAAfAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
@@ -47,42 +132,39 @@
},
{
"$type": "Document",
- "DocumentIndex": 1,
+ "DocumentIndex": 6,
"Title": "CompProperties_PawnFlight.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs",
+ "DocumentMoniker": "D:\\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",
+ "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_Flight\\CompProperties_PawnFlight.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA4AAAAeAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-01-22T14:02:45.434Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-01-22T14:02:45.434Z"
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 8,
"Title": "HediffComp_ProductionQueue.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\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": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\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": "AgIAAAAAAAAAAAAAAAAAAB8AAAAMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-01-22T10:31:06.201Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-01-22T10:31:06.201Z"
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 7,
"Title": "HediffCompProperties_ProductionQueue.cs",
- "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ProductionQueue\\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": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\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": "AgIAAB8AAAAAAAAAAAAewEoAAAApAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-01-22T09:30:17.721Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-01-22T09:30:17.721Z"
}
]
}
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 4728668..83c33fd 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -34,6 +34,9 @@
4
+
+
+
@@ -311,6 +314,7 @@
+
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/Building_CorpseVat.cs b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/Building_CorpseVat.cs
index f9755cc..5e53a66 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/Building_CorpseVat.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/Building_CorpseVat.cs
@@ -1,356 +1,799 @@
using RimWorld;
+using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
using Verse;
using Verse.AI;
+using Verse.Sound;
namespace ArachnaeSwarm
{
- public class Building_CorpseContainer : Building_Enterable, IThingHolder, ISuspendableThingHolder
+ [StaticConstructorOnStartup]
+ public class Building_CorpseVat : Building, IThingHolder, ISuspendableThingHolder, ISearchableContents
{
- private ThingOwner corpseContainer;
- private Corpse storedCorpse;
+ #region 静态构造函数和常量
+ private static readonly Texture2D InsertCorpseIcon = ContentFinder.Get("UI/Commands/InsertCorpse", false);
+ private static readonly Texture2D EjectCorpseIcon = ContentFinder.Get("UI/Commands/EjectCorpse", false);
+ private static readonly Texture2D FindCorpseIcon = ContentFinder.Get("UI/Commands/FindCorpse", false);
- // 公开接口:查询是否有尸体
- public bool HasCorpse => corpseContainer.Any;
-
- // 公开接口:获取存储的尸体(如果存在)
- public Corpse StoredCorpse => storedCorpse;
-
- // 公开接口:获取所有存储的物体(用于兼容性)
- public IEnumerable StoredThings => corpseContainer;
-
- // 公开接口:获取尸体数量
- public int CorpseCount => corpseContainer.Count;
+ // 工作定义
+ private static readonly JobDef HaulCorpseToVatJobDef = DefDatabase.GetNamedSilentFail("ARA_HaulCorpseToVat");
+ private const int MaxDistanceForAutoAssignment = 30; // 自动分配工作的最大距离
+ #endregion
- public Building_CorpseContainer()
+ #region 字段和属性
+ public ThingOwner innerContainer;
+ private Corpse selectedCorpse;
+ private int startTick = -1;
+ private Graphic cachedTopGraphic;
+ private CompPowerTrader powerComp;
+ private CorpseVatExtension vatExtension;
+
+ // 绘制相关
+ private Vector3 corpseDrawOffset = Vector3.zero;
+ private float corpseDrawRotation = 0f;
+ private float corpseDrawScale = 1f;
+
+ public bool Working => startTick >= 0;
+ public Corpse SelectedCorpse => selectedCorpse;
+ public bool HasCorpse => selectedCorpse != null && innerContainer.Contains(selectedCorpse);
+ public virtual bool IsContentsSuspended => true;
+ public ThingOwner SearchableContents => innerContainer;
+ public CompPowerTrader PowerComp => powerComp ??= GetComp();
+
+ // 扩展属性
+ public CorpseVatExtension VatExtension => vatExtension ??= def.GetModExtension();
+
+ // 顶部图形
+ private Graphic TopGraphic
{
- corpseContainer = new ThingOwner(this);
+ get
+ {
+ if (cachedTopGraphic == null && VatExtension != null && !VatExtension.topGraphicPath.NullOrEmpty())
+ {
+ cachedTopGraphic = GraphicDatabase.Get(
+ VatExtension.graphicClass ?? typeof(Graphic_Multi),
+ VatExtension.topGraphicPath,
+ ShaderDatabase.Transparent,
+ def.graphicData.drawSize,
+ Color.white,
+ Color.white
+ );
+ }
+ return cachedTopGraphic;
+ }
+ }
+ #endregion
+
+ #region 构造函数
+ public Building_CorpseVat()
+ {
+ innerContainer = new ThingOwner(this);
+ }
+ #endregion
+
+ #region 基础方法
+ public override void SpawnSetup(Map map, bool respawningAfterLoad)
+ {
+ base.SpawnSetup(map, respawningAfterLoad);
+
+ // 初始化绘制参数
+ if (VatExtension != null)
+ {
+ corpseDrawOffset = VatExtension.corpseDrawOffset;
+ corpseDrawRotation = VatExtension.corpseDrawRotation;
+ corpseDrawScale = VatExtension.corpseDrawScale;
+ }
+
+ // 加载时恢复选择
+ if (respawningAfterLoad && selectedCorpse != null)
+ {
+ // 检查尸体是否仍然有效
+ if (selectedCorpse.Destroyed || !innerContainer.Contains(selectedCorpse))
+ {
+ selectedCorpse = null;
+ startTick = -1;
+ }
+ else
+ {
+ startTick = Math.Max(startTick, 0);
+ }
+ }
}
- public override AcceptanceReport CanAcceptPawn(Pawn p)
+ public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
{
- // 这个建筑不接受活人,只接受尸体
- // 实际上我们通过特殊方式处理尸体
- return "CorpseContainer_OnlyAcceptsCorpses".Translate();
+ // 在建筑被移除前,弹出所有内容
+ if (mode != DestroyMode.WillReplace)
+ {
+ EjectContents();
+ }
+ base.DeSpawn(mode);
}
- public override void TryAcceptPawn(Pawn p)
+ public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
{
- // 不接受活人
- Messages.Message("CorpseContainer_CannotAcceptLivingPawn".Translate(p.LabelShort), MessageTypeDefOf.RejectInput);
+ // 在建筑被销毁前,弹出所有内容
+ if (mode != DestroyMode.WillReplace)
+ {
+ EjectContents();
+ }
+ base.Destroy(mode);
}
+ #endregion
+ #region 尸体管理
///
- /// 尝试接收尸体
+ /// 检查是否可以接受尸体
///
- public AcceptanceReport TryAcceptCorpse(Corpse corpse)
+ public AcceptanceReport CanAcceptCorpse(Corpse corpse)
{
+ // 检查是否正在工作
+ if (Working && selectedCorpse != null && selectedCorpse != corpse)
+ {
+ return "CorpseVat_Occupied".Translate();
+ }
+
+ // 检查是否有电源需求且是否供电
+ if (VatExtension != null && VatExtension.requiresPower && (PowerComp == null || !PowerComp.PowerOn))
+ {
+ return "CorpseVat_NoPower".Translate();
+ }
+
+ // 检查尸体是否有效
if (corpse == null || corpse.Destroyed)
- return false;
-
- if (corpseContainer.Count >= GetMaxCapacity())
{
- return "CorpseContainer_Full".Translate();
+ return "CorpseVat_InvalidCorpse".Translate();
}
- // 检查是否已经包含了这个尸体
- if (corpseContainer.Contains(corpse))
+ // 检查尸体是否在地图上
+ if (!corpse.Spawned)
{
- return "CorpseContainer_AlreadyContainsCorpse".Translate(corpse.LabelShort);
+ return "CorpseVat_CorpseNotSpawned".Translate();
}
- // 尝试将尸体放入容器
- bool success = false;
+ return true;
+ }
+
+ ///
+ /// 尝试接受尸体
+ ///
+ public void TryAcceptCorpse(Corpse corpse)
+ {
+ AcceptanceReport report = CanAcceptCorpse(corpse);
+ if (!report.Accepted)
+ {
+ Messages.Message(report.Reason, MessageTypeDefOf.RejectInput);
+ return;
+ }
+ // 如果已经有一个选择的尸体,清除它
+ if (selectedCorpse != null && selectedCorpse != corpse)
+ {
+ ClearSelectedCorpse();
+ }
+
+ selectedCorpse = corpse;
+
+ // 如果尸体已经在地图上,创建搬运工作
if (corpse.Spawned)
+ {
+ AssignHaulJobForCorpse(corpse);
+ }
+ }
+
+ ///
+ /// 直接放入尸体(用于搬运工作完成时调用)
+ ///
+ public void InsertCorpse(Corpse corpse)
+ {
+ if (!CanAcceptCorpse(corpse).Accepted)
+ return;
+
+ bool wasSpawned = corpse.Spawned;
+ if (wasSpawned)
{
corpse.DeSpawn();
- success = corpseContainer.TryAdd(corpse, true);
+ }
+
+ if (innerContainer.TryAddOrTransfer(corpse))
+ {
+ selectedCorpse = corpse;
+ startTick = Find.TickManager.TicksGame;
+
+ // 播放音效
+ if (VatExtension != null && VatExtension.insertSound != null)
+ {
+ VatExtension.insertSound.PlayOneShot(new TargetInfo(Position, Map));
+ }
+
+ // 发送消息
+ Messages.Message("CorpseVat_CorpseInserted".Translate(corpse.InnerPawn?.LabelShortCap ?? "Unknown"),
+ MessageTypeDefOf.PositiveEvent);
}
else
{
- success = corpseContainer.TryAdd(corpse, true);
+ Messages.Message("CorpseVat_FailedToInsert".Translate(), MessageTypeDefOf.RejectInput);
}
-
- if (success)
- {
- storedCorpse = corpse;
- OnCorpseAdded(corpse);
- return true;
- }
-
- return "CorpseContainer_FailedToAddCorpse".Translate(corpse.LabelShort);
}
-
+
///
- /// 移除尸体
+ /// 弹出所有内容
///
- public bool TryRemoveCorpse(Corpse corpse)
+ public void EjectContents()
{
- if (corpse == null || !corpseContainer.Contains(corpse))
+ if (!HasCorpse)
+ return;
+
+ try
+ {
+ // 弹出选中的尸体
+ if (innerContainer.Contains(selectedCorpse))
+ {
+ if (innerContainer.TryDrop(selectedCorpse, InteractionCell, Map, ThingPlaceMode.Near, out var droppedCorpse))
+ {
+ // 播放音效
+ if (VatExtension != null && VatExtension.ejectSound != null)
+ {
+ VatExtension.ejectSound.PlayOneShot(new TargetInfo(Position, Map));
+ }
+
+ // 发送消息
+ Messages.Message("CorpseVat_CorpseEjected".Translate(droppedCorpse.InnerPawn?.LabelShortCap ?? "Unknown"),
+ MessageTypeDefOf.NeutralEvent);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Error ejecting corpse from CorpseVat: {ex}");
+ }
+ finally
+ {
+ ClearSelectedCorpse();
+ }
+ }
+
+ ///
+ /// 清除选中的尸体
+ ///
+ private void ClearSelectedCorpse()
+ {
+ selectedCorpse = null;
+ startTick = -1;
+ }
+ #endregion
+
+ #region 工作分配
+ ///
+ /// 为尸体分配搬运工作
+ ///
+ private void AssignHaulJobForCorpse(Corpse corpse)
+ {
+ // 查找最近的殖民者
+ Pawn bestHauler = FindBestHaulerForCorpse(corpse);
+
+ if (bestHauler == null)
+ {
+ Messages.Message("CorpseVat_NoAvailableHauler".Translate(), MessageTypeDefOf.RejectInput);
+ return;
+ }
+
+ // 创建工作
+ Job haulJob = CreateHaulJobForCorpse(corpse, bestHauler);
+ if (haulJob != null)
+ {
+ bestHauler.jobs.TryTakeOrderedJob(haulJob, JobTag.MiscWork);
+ Messages.Message("CorpseVat_HaulJobAssigned".Translate(bestHauler.LabelShort, corpse.InnerPawn?.LabelShortCap ?? "Unknown"),
+ MessageTypeDefOf.NeutralEvent);
+ }
+ else
+ {
+ Messages.Message("CorpseVat_FailedToCreateJob".Translate(), MessageTypeDefOf.RejectInput);
+ }
+ }
+
+ ///
+ /// 查找最佳的搬运者
+ ///
+ private Pawn FindBestHaulerForCorpse(Corpse corpse)
+ {
+ if (corpse == null || !corpse.Spawned)
+ return null;
+
+ List allColonists = Map.mapPawns.FreeColonistsSpawned.ToList();
+ if (allColonists.Count == 0)
+ return null;
+
+ // 按距离排序
+ allColonists.Sort((a, b) =>
+ a.Position.DistanceTo(corpse.Position).CompareTo(b.Position.DistanceTo(corpse.Position))
+ );
+
+ // 查找第一个符合条件的殖民者
+ foreach (Pawn colonist in allColonists)
+ {
+ if (IsValidHauler(colonist, corpse))
+ {
+ return colonist;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// 检查是否为有效的搬运者
+ ///
+ private bool IsValidHauler(Pawn hauler, Corpse corpse)
+ {
+ if (hauler == null || hauler.Downed || hauler.Dead || !hauler.Spawned)
return false;
- bool removed = corpseContainer.TryRemove(corpse);
- if (removed)
- {
- if (storedCorpse == corpse)
- storedCorpse = null;
-
- OnCorpseRemoved(corpse);
- TryDropCorpseAt(corpse, Position, Map);
- }
-
- return removed;
- }
-
- ///
- /// 清空容器
- ///
- public void ClearContainer()
- {
- List corpsesToRemove = new List(corpseContainer);
-
- foreach (Corpse corpse in corpsesToRemove)
- {
- TryRemoveCorpse(corpse);
- }
-
- storedCorpse = null;
- }
-
- ///
- /// 获取最大容量
- ///
- public virtual int GetMaxCapacity()
- {
- // 默认容量为1,可以在XML中通过扩展属性修改
- var extension = def.GetModExtension();
- return extension?.maxCapacity ?? 1;
- }
-
- ///
- /// 尸体添加时的回调
- ///
- protected virtual void OnCorpseAdded(Corpse corpse)
- {
- // 可以在这里添加音效、视觉效果等
- // SoundDefOf.ThingInstalled.PlayOneShot(new TargetInfo(Position, Map));
- }
-
- ///
- /// 尸体移除时的回调
- ///
- protected virtual void OnCorpseRemoved(Corpse corpse)
- {
- // 可以在这里添加音效、视觉效果等
- // SoundDefOf.ThingUninstalled.PlayOneShot(new TargetInfo(Position, Map));
- }
-
- ///
- /// 尝试在指定位置放置尸体
- ///
- protected virtual bool TryDropCorpseAt(Corpse corpse, IntVec3 dropLoc, Map map)
- {
- if (corpse == null || map == null)
+ // 检查是否能够搬运
+ if (!hauler.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
return false;
- // 尝试在交互单元格放置
- IntVec3 targetCell = InteractionCell;
-
- // 如果交互单元格被阻挡,尝试附近的单元格
- if (!targetCell.Walkable(map) || targetCell.GetEdifice(map) != null)
+ // 检查是否可以到达尸体和建筑
+ if (!hauler.CanReach(corpse, PathEndMode.Touch, Danger.Some) ||
+ !hauler.CanReach(this, PathEndMode.InteractionCell, Danger.Some))
{
- targetCell = GenAdj.CellsAdjacent8Way(this).RandomElement();
+ return false;
}
- // 确保目标单元格可通行
- if (!targetCell.Walkable(map))
+ // 检查距离限制
+ float distanceToCorpse = hauler.Position.DistanceTo(corpse.Position);
+ if (distanceToCorpse > MaxDistanceForAutoAssignment)
{
- targetCell = Position; // 如果都不行,放在建筑自己的位置
+ return false;
}
- // 放置尸体
- bool placed = GenPlace.TryPlaceThing(corpse, targetCell, map, ThingPlaceMode.Near);
-
- if (!placed)
- {
- // 如果还是失败,尝试直接生成
- corpse.SpawnSetup(map, false);
- }
-
- return placed;
+ return true;
}
-
+
///
- /// 获取Gizmos
+ /// 创建搬运工作
///
+ private Job CreateHaulJobForCorpse(Corpse corpse, Pawn hauler)
+ {
+ if (HaulCorpseToVatJobDef == null)
+ {
+ // 使用默认的搬运工作
+ return JobMaker.MakeJob(JobDefOf.HaulToContainer, corpse, this);
+ }
+ else
+ {
+ // 使用自定义工作
+ return JobMaker.MakeJob(HaulCorpseToVatJobDef, corpse, this);
+ }
+ }
+ #endregion
+
+ #region Gizmos
public override IEnumerable GetGizmos()
{
foreach (Gizmo gizmo in base.GetGizmos())
{
yield return gizmo;
}
-
- // 清空按钮
- if (corpseContainer.Any)
+
+ // 弹出按钮
+ if (HasCorpse)
{
- Command_Action clearCommand = new Command_Action
+ Command_Action ejectCommand = new Command_Action
{
- defaultLabel = "CorpseContainer_Clear".Translate(),
- defaultDesc = "CorpseContainer_ClearDesc".Translate(),
- icon = TexCommand.ClearPrioritizedWork,
- action = ClearContainer
+ defaultLabel = "CorpseVat_Eject".Translate(),
+ defaultDesc = "CorpseVat_EjectDesc".Translate(),
+ icon = EjectCorpseIcon,
+ action = EjectContents,
+ hotKey = KeyBindingDefOf.Misc1
+ };
+ yield return ejectCommand;
+ }
+ else
+ {
+ // 选择尸体按钮
+ Command_Action selectCommand = new Command_Action
+ {
+ defaultLabel = "CorpseVat_SelectCorpse".Translate(),
+ defaultDesc = "CorpseVat_SelectCorpseDesc".Translate(),
+ icon = InsertCorpseIcon,
+ action = OpenCorpseSelectionMenu,
+ hotKey = KeyBindingDefOf.Misc2
};
- yield return clearCommand;
+ // 如果没有可用的尸体,禁用按钮
+ if (!GetAvailableCorpses().Any())
+ {
+ selectCommand.Disable("CorpseVat_NoCorpsesAvailable".Translate());
+ }
+
+ yield return selectCommand;
+
+ // 查找尸体按钮
+ Command_Action findCommand = new Command_Action
+ {
+ defaultLabel = "CorpseVat_FindCorpse".Translate(),
+ defaultDesc = "CorpseVat_FindCorpseDesc".Translate(),
+ icon = FindCorpseIcon,
+ action = () => FindAllCorpsesAndCreateJobs(),
+ hotKey = KeyBindingDefOf.Misc3
+ };
+ yield return findCommand;
}
- // 取出特定尸体的按钮(如果有多个尸体)
- if (corpseContainer.Count > 1)
+ // 显示内容
+ foreach (Thing thing in innerContainer)
{
- Command_Action removeSpecificCommand = new Command_Action
+ Gizmo gizmo = Building.SelectContainedItemGizmo(this, thing);
+ if (gizmo != null)
{
- defaultLabel = "CorpseContainer_RemoveSpecific".Translate(),
- defaultDesc = "CorpseContainer_RemoveSpecificDesc".Translate(),
- icon = TexCommand.RemoveFromContainer,
- action = () =>
- {
- List options = new List();
-
- foreach (Corpse corpse in corpseContainer)
- {
- options.Add(new FloatMenuOption(
- corpse.LabelCap,
- () => TryRemoveCorpse(corpse),
- corpse.InnerPawn?.RaceProps?.FleshType?.IconTex() ?? BaseContent.BadTex,
- Color.white
- ));
- }
-
- if (options.Any())
- {
- Find.WindowStack.Add(new FloatMenu(options));
- }
- }
- };
-
- yield return removeSpecificCommand;
+ yield return gizmo;
+ }
}
}
-
+
///
- /// 获取浮动菜单选项
+ /// 打开尸体选择菜单
///
- public override IEnumerable GetFloatMenuOptions(Pawn selPawn)
+ private void OpenCorpseSelectionMenu()
{
- foreach (FloatMenuOption option in base.GetFloatMenuOptions(selPawn))
+ List options = new List();
+ var availableCorpses = GetAvailableCorpses();
+
+ if (!availableCorpses.Any())
{
- yield return option;
+ options.Add(new FloatMenuOption("CorpseVat_NoCorpsesAvailable".Translate(), null));
+ }
+ else
+ {
+ foreach (Corpse corpse in availableCorpses)
+ {
+ string label = GetCorpseLabel(corpse);
+ options.Add(new FloatMenuOption(
+ label,
+ () => TryAcceptCorpse(corpse),
+ corpse.InnerPawn,
+ Color.white
+ ));
+ }
}
- // 添加"存储尸体"选项
- if (selPawn.CanReach(this, PathEndMode.InteractionCell, Danger.Deadly))
+ Find.WindowStack.Add(new FloatMenu(options));
+ }
+
+ ///
+ /// 查找所有尸体并创建工作
+ ///
+ private void FindAllCorpsesAndCreateJobs()
+ {
+ var availableCorpses = GetAvailableCorpses();
+ int jobsCreated = 0;
+
+ foreach (Corpse corpse in availableCorpses)
{
- // 查找附近可搬运的尸体
- foreach (Thing thing in GenAdj.CellsAdjacent8Way(this)
- .SelectMany(cell => cell.GetThingList(Map))
- .Distinct())
+ // 为每个尸体创建搬运工作
+ Pawn hauler = FindBestHaulerForCorpse(corpse);
+ if (hauler != null)
{
- if (thing is Corpse corpse && corpse.InnerPawn != null)
+ Job haulJob = CreateHaulJobForCorpse(corpse, hauler);
+ if (haulJob != null)
{
- yield return new FloatMenuOption(
- "CorpseContainer_StoreCorpse".Translate(corpse.LabelCap),
- () =>
- {
- // 创建搬运工作
- Job job = JobMaker.MakeJob(JobDefOf.HaulCorpseToContainer, corpse, this);
- job.count = 1;
- selPawn.jobs.TryTakeOrderedJob(job, JobTag.MiscWork);
- },
- MenuOptionPriority.Default,
- null,
- corpse
- );
+ hauler.jobs.TryTakeOrderedJob(haulJob, JobTag.MiscWork);
+ jobsCreated++;
+ }
+ }
+ }
+
+ if (jobsCreated > 0)
+ {
+ Messages.Message("CorpseVat_JobsCreated".Translate(jobsCreated), MessageTypeDefOf.PositiveEvent);
+ }
+ else
+ {
+ Messages.Message("CorpseVat_NoJobsCreated".Translate(), MessageTypeDefOf.NeutralEvent);
+ }
+ }
+
+ ///
+ /// 获取可用的尸体列表
+ ///
+ private IEnumerable GetAvailableCorpses()
+ {
+ if (Map == null)
+ yield break;
+
+ foreach (Thing thing in Map.listerThings.ThingsOfDef(ThingDefOf.Corpse))
+ {
+ Corpse corpse = thing as Corpse;
+ if (corpse != null && CanAcceptCorpse(corpse).Accepted)
+ {
+ yield return corpse;
+ }
+ }
+ }
+
+ ///
+ /// 获取尸体的显示标签
+ ///
+ private string GetCorpseLabel(Corpse corpse)
+ {
+ if (corpse == null)
+ return "Unknown";
+
+ Pawn innerPawn = corpse.InnerPawn;
+ if (innerPawn == null)
+ return "CorpseVat_UnknownCorpse".Translate();
+
+ // 显示距离信息
+ float distance = corpse.Position.DistanceTo(Position);
+ string distanceStr = distance.ToString("F0") + "m";
+
+ // 显示死亡原因(如果有)
+ string cause = "";
+ if (corpse.InnerPawn.health?.hediffSet != null)
+ {
+ Hediff leadingHediff = corpse.InnerPawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def.lethalSeverity > 0);
+ if (leadingHediff != null)
+ {
+ cause = $" ({leadingHediff.def.label})";
+ }
+ }
+
+ return $"{innerPawn.LabelCap} ({distanceStr}){cause}";
+ }
+ #endregion
+
+ #region Tick和绘制
+ protected override void Tick()
+ {
+ base.Tick();
+
+ // 检查电源
+ if (VatExtension != null && VatExtension.requiresPower && (PowerComp == null || !PowerComp.PowerOn))
+ {
+ if (HasCorpse)
+ {
+ Messages.Message("CorpseVat_PowerLost".Translate(), MessageTypeDefOf.CautionInput);
+ EjectContents();
+ }
+ return;
+ }
+
+ // 检查尸体状态
+ if (HasCorpse && (selectedCorpse.Destroyed || !innerContainer.Contains(selectedCorpse)))
+ {
+ ClearSelectedCorpse();
+ return;
+ }
+
+ // 应用保存效果(减缓腐烂)
+ if (HasCorpse && VatExtension != null && VatExtension.slowDecayRate > 0)
+ {
+ // 减缓腐烂速度
+ CompRottable rottable = selectedCorpse.TryGetComp();
+ if (rottable != null && rottable.PropsRot != null)
+ {
+ // 这里可以修改腐烂速度,但需要反射访问私有字段
+ // 暂时只记录日志
+ if (Find.TickManager.TicksGame % 2500 == 0) // 每游戏小时记录一次
+ {
+ Log.Message($"CorpseVat slowing decay: {selectedCorpse.InnerPawn?.LabelCap ?? "Unknown"}");
}
}
}
}
-
+
+ protected override void DrawAt(Vector3 drawLoc, bool flip = false)
+ {
+ base.DrawAt(drawLoc, flip);
+
+ // 绘制顶部图形
+ if (TopGraphic != null)
+ {
+ TopGraphic.Draw(drawLoc + Altitudes.AltIncVect * 2f, Rotation, this);
+ }
+
+ // 绘制尸体
+ if (HasCorpse)
+ {
+ DrawCorpse(drawLoc);
+ }
+ }
+
///
- /// 获取检查字符串
+ /// 绘制尸体
///
+ private void DrawCorpse(Vector3 drawLoc)
+ {
+ if (selectedCorpse == null)
+ return;
+
+ // 获取尸体的绘制位置
+ Vector3 corpseDrawPos = drawLoc + corpseDrawOffset;
+
+ // 调整高度
+ corpseDrawPos.y += Altitudes.AltIncVect.y * 3f;
+
+ // 绘制尸体
+ // 注意:由于尸体在容器中,其正常绘制方法可能不会自动调用
+ // 我们需要手动调用绘制方法
+ selectedCorpse.DrawAt(corpseDrawPos);
+
+ // 如果需要特殊的绘制效果,可以在这里添加
+ if (VatExtension != null && VatExtension.drawPreservationEffect)
+ {
+ DrawPreservationEffect(corpseDrawPos);
+ }
+ }
+
+ ///
+ /// 绘制保存效果
+ ///
+ private void DrawPreservationEffect(Vector3 position)
+ {
+ if (Find.TickManager.TicksGame % 30 == 0)
+ {
+ FleckMaker.ThrowLightningGlow(position, Map, 0.5f);
+ }
+ }
+ #endregion
+
+ #region 检查和信息
public override string GetInspectString()
{
- string baseString = base.GetInspectString();
+ StringBuilder sb = new StringBuilder();
+ sb.Append(base.GetInspectString());
- string corpseInfo = string.Empty;
+ if (sb.Length > 0)
+ sb.AppendLine();
- if (corpseContainer.Any)
+ // 电源状态
+ if (VatExtension != null && VatExtension.requiresPower)
{
- int count = corpseContainer.Count;
- int max = GetMaxCapacity();
-
- corpseInfo = "CorpseContainer_Contains".Translate(count, max);
-
- if (count == 1 && storedCorpse != null)
+ if (PowerComp == null)
{
- corpseInfo += ": " + storedCorpse.LabelCap;
+ sb.Append("CorpseVat_NoPowerComp".Translate());
+ }
+ else if (!PowerComp.PowerOn)
+ {
+ sb.Append("CorpseVat_PowerOff".Translate());
+ }
+ else
+ {
+ sb.Append("CorpseVat_PowerOn".Translate());
+ }
+ sb.AppendLine();
+ }
+
+ // 内容状态
+ if (HasCorpse)
+ {
+ Pawn innerPawn = selectedCorpse.InnerPawn;
+ if (innerPawn != null)
+ {
+ sb.Append("CorpseVat_Contains".Translate(innerPawn.LabelCap));
+ sb.AppendLine();
- // 显示尸体的信息
- Pawn innerPawn = storedCorpse.InnerPawn;
- if (innerPawn != null)
+ // 显示保存时间
+ if (startTick > 0)
{
- corpseInfo += " (" + innerPawn.KindLabel + ")";
+ int ticksInVat = Find.TickManager.TicksGame - startTick;
+ string timeStr = ticksInVats.ToStringTicksToPeriod();
+ sb.Append("CorpseVat_PreservationTime".Translate(timeStr));
+ sb.AppendLine();
+ }
+
+ // 显示腐烂状态
+ CompRottable rottable = selectedCorpse.TryGetComp();
+ if (rottable != null)
+ {
+ sb.Append("CorpseVat_RotProgress".Translate(rottable.RotProgress.ToStringPercent()));
+ sb.AppendLine();
}
}
}
else
{
- corpseInfo = "CorpseContainer_Empty".Translate();
+ sb.Append("CorpseVat_Empty".Translate());
}
- if (!string.IsNullOrEmpty(baseString))
- return baseString + "\n" + corpseInfo;
- else
- return corpseInfo;
+ return sb.ToString().TrimEndNewlines();
}
+
+ public override void DrawExtraSelectionOverlays()
+ {
+ base.DrawExtraSelectionOverlays();
+
+ // 如果选择了尸体但未放入,显示连接线
+ if (selectedCorpse != null && !innerContainer.Contains(selectedCorpse) && selectedCorpse.Spawned)
+ {
+ GenDraw.DrawLineBetween(this.TrueCenter(), selectedCorpse.TrueCenter());
+ }
+ }
+ #endregion
- ///
- /// 保存数据
- ///
+ #region IThingHolder接口实现
+ public void GetChildHolders(List outChildren)
+ {
+ ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
+ }
+
+ public ThingOwner GetDirectlyHeldThings()
+ {
+ return innerContainer;
+ }
+ #endregion
+
+ #region 序列化
public override void ExposeData()
{
base.ExposeData();
-
- Scribe_Deep.Look(ref corpseContainer, "corpseContainer", this);
- Scribe_References.Look(ref storedCorpse, "storedCorpse");
-
- if (Scribe.mode == LoadSaveMode.PostLoadInit)
- {
- // 确保storedCorpse是最新存储的尸体
- if (corpseContainer.Any && storedCorpse == null)
- {
- storedCorpse = corpseContainer[0];
- }
- else if (storedCorpse != null && !corpseContainer.Contains(storedCorpse))
- {
- storedCorpse = corpseContainer.Any ? corpseContainer[0] : null;
- }
- }
+ Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
+ Scribe_References.Look(ref selectedCorpse, "selectedCorpse");
+ Scribe_Values.Look(ref startTick, "startTick", -1);
+ Scribe_Values.Look(ref corpseDrawOffset, "corpseDrawOffset", Vector3.zero);
+ Scribe_Values.Look(ref corpseDrawRotation, "corpseDrawRotation", 0f);
+ Scribe_Values.Look(ref corpseDrawScale, "corpseDrawScale", 1f);
}
+ #endregion
+ #region 调试和工具方法
///
- /// 销毁时处理
+ /// 获取调试信息
///
- public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
+ public string GetDebugInfo()
{
- if (mode != DestroyMode.WillReplace)
+ StringBuilder sb = new StringBuilder();
+ sb.AppendLine("=== Building_CorpseVat 调试信息 ===");
+ sb.AppendLine($"建筑: {LabelCap}");
+ sb.AppendLine($"是否有尸体: {HasCorpse}");
+ sb.AppendLine($"是否工作中: {Working}");
+ sb.AppendLine($"开始Tick: {startTick}");
+ sb.AppendLine($"电源: {(PowerComp?.PowerOn == true ? "开启" : "关闭")}");
+
+ if (HasCorpse)
{
- // 将尸体全部弹出
- corpseContainer.TryDropAll(Position, Map, ThingPlaceMode.Near);
+ sb.AppendLine($"尸体: {selectedCorpse.InnerPawn?.LabelCap ?? "Unknown"}");
+ sb.AppendLine($"尸体位置: {selectedCorpse.Position}");
+ sb.AppendLine($"容器中的数量: {innerContainer.Count}");
}
- base.DeSpawn(mode);
+ sb.AppendLine($"扩展配置: {(VatExtension != null ? "已加载" : "未找到")}");
+ if (VatExtension != null)
+ {
+ sb.AppendLine($"需要电源: {VatExtension.requiresPower}");
+ sb.AppendLine($"减缓腐烂: {VatExtension.slowDecayRate}");
+ sb.AppendLine($"顶部贴图: {VatExtension.topGraphicPath}");
+ }
+
+ return sb.ToString();
}
+
+ ///
+ /// 获取所有可用尸体的统计信息
+ ///
+ public string GetAvailableCorpsesInfo()
+ {
+ StringBuilder sb = new StringBuilder();
+ var corpses = GetAvailableCorpses().ToList();
+
+ sb.AppendLine("=== 可用尸体列表 ===");
+ sb.AppendLine($"总计: {corpses.Count}");
+ sb.AppendLine();
+
+ foreach (Corpse corpse in corpses)
+ {
+ sb.AppendLine(GetCorpseLabel(corpses));
+ sb.AppendLine($" 位置: {corpse.Position}");
+ sb.AppendLine($" 距离: {corpse.Position.DistanceTo(Position):F0}m");
+ sb.AppendLine();
+ }
+
+ return sb.ToString();
+ }
+ #endregion
}
}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/CorpseVatExtension.cs b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/CorpseVatExtension.cs
new file mode 100644
index 0000000..e15ecc1
--- /dev/null
+++ b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/CorpseVatExtension.cs
@@ -0,0 +1,45 @@
+using System;
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ ///
+ /// 尸体保存建筑的扩展定义
+ ///
+ public class CorpseVatExtension : DefModExtension
+ {
+ // ===== 贴图配置 =====
+ public string topGraphicPath; // 顶部贴图路径
+ public Type graphicClass = typeof(Graphic_Multi); // 贴图类
+
+ // ===== 尸体绘制配置 =====
+ public Vector3 corpseDrawOffset = Vector3.zero; // 尸体绘制偏移
+ public float corpseDrawRotation = 0f; // 尸体绘制旋转
+ public float corpseDrawScale = 1f; // 尸体绘制缩放
+ public bool drawPreservationEffect = true; // 是否绘制保存效果
+
+ // ===== 功能配置 =====
+ public bool requiresPower = true; // 是否需要电源
+ public float slowDecayRate = 0.1f; // 腐烂减缓率(0-1,0=完全停止腐烂,1=正常腐烂)
+
+ // ===== 音效配置 =====
+ public SoundDef insertSound; // 放入音效
+ public SoundDef ejectSound; // 弹出音效
+
+ public string GetConfigSummary()
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ sb.AppendLine("=== CorpseVat 配置摘要 ===");
+ sb.AppendLine($"需要电源: {requiresPower}");
+ sb.AppendLine($"减缓腐烂: {(slowDecayRate * 100):F0}%");
+ sb.AppendLine($"顶部贴图: {topGraphicPath ?? "无"}");
+ sb.AppendLine($"绘制偏移: {corpseDrawOffset}");
+ sb.AppendLine($"绘制旋转: {corpseDrawRotation}");
+ sb.AppendLine($"绘制缩放: {corpseDrawScale}");
+
+ return sb.ToString();
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/DefModExtension_CorpseContainer.cs b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/DefModExtension_CorpseContainer.cs
deleted file mode 100644
index 523b22b..0000000
--- a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/DefModExtension_CorpseContainer.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Verse;
-
-namespace ArachnaeSwarm
-{
- public class DefModExtension_CorpseContainer : DefModExtension
- {
- // 最大容量
- public int maxCapacity = 1;
-
- // 是否允许存储非人类尸体
- public bool allowNonHumanCorpses = true;
-
- // 是否允许存储腐烂的尸体
- public bool allowRottingCorpses = true;
-
- // 是否自动保鲜(防止腐烂)
- public bool preserveCorpses = false;
-
- // 自定义存储效果描述
- public string storageEffectDescriptionKey;
- }
-}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToContainer.cs b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToContainer.cs
deleted file mode 100644
index 329f0c9..0000000
--- a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToContainer.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using RimWorld;
-using Verse;
-using Verse.AI;
-
-namespace ArachnaeSwarm
-{
- public class JobDriver_HaulCorpseToContainer : JobDriver
- {
- private const TargetIndex CorpseIndex = TargetIndex.A;
- private const TargetIndex ContainerIndex = TargetIndex.B;
- private const TargetIndex StoreCellIndex = TargetIndex.C;
-
- private Corpse Corpse => (Corpse)job.GetTarget(CorpseIndex).Thing;
- private Building_CorpseContainer Container => (Building_CorpseContainer)job.GetTarget(ContainerIndex).Thing;
-
- public override bool TryMakePreToilReservations(bool errorOnFailed)
- {
- return pawn.Reserve(Corpse, job, 1, -1, null, errorOnFailed) &&
- pawn.Reserve(Container, job, 1, -1, null, errorOnFailed);
- }
-
- protected override IEnumerable MakeNewToils()
- {
- // 验证目标
- this.FailOnDestroyedOrNull(CorpseIndex);
- this.FailOnDestroyedOrNull(ContainerIndex);
- this.FailOnForbidden(CorpseIndex);
- this.FailOnForbidden(ContainerIndex);
-
- // 前往尸体
- yield return Toils_Goto.GotoThing(CorpseIndex, PathEndMode.Touch)
- .FailOnSomeonePhysicallyInteracting(CorpseIndex);
-
- // 捡起尸体
- yield return Toils_Haul.StartCarryThing(CorpseIndex);
-
- // 前往容器
- yield return Toils_Goto.GotoThing(ContainerIndex, PathEndMode.InteractionCell);
-
- // 存储尸体到容器
- Toil storeToil = new Toil();
- storeToil.initAction = delegate
- {
- if (pawn.carryTracker.CarriedThing is Corpse carriedCorpse)
- {
- AcceptanceReport report = Container.TryAcceptCorpse(carriedCorpse);
-
- if (report.Accepted)
- {
- // 尸体已成功存储,清空搬运
- pawn.carryTracker.innerContainer.Clear();
- }
- else
- {
- // 存储失败,结束工作
- EndJobWith(JobCondition.Incompletable);
- }
- }
- };
- storeToil.defaultCompleteMode = ToilCompleteMode.Instant;
- yield return storeToil;
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToVat.cs b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToVat.cs
new file mode 100644
index 0000000..5cfd19d
--- /dev/null
+++ b/Source/ArachnaeSwarm/Buildings/Building_CorpseVat/JobDriver_HaulCorpseToVat.cs
@@ -0,0 +1,73 @@
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ ///
+ /// 自定义的搬运尸体工作驱动
+ ///
+ public class JobDriver_HaulCorpseToVat : JobDriver_HaulToContainer
+ {
+ protected override Toil CarryToContainerToil()
+ {
+ Toil toil = base.CarryToContainerToil();
+
+ // 添加自定义行为
+ toil.AddPreTickAction(() =>
+ {
+ Corpse corpse = TargetThingA as Corpse;
+ Building_CorpseVat vat = TargetThingB as Building_CorpseVat;
+
+ if (corpse != null && vat != null && pawn != null)
+ {
+ // 检查距离,如果太远可以取消工作
+ float distance = corpse.Position.DistanceTo(vat.Position);
+ if (distance > 100f) // 最大距离限制
+ {
+ pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
+ }
+ }
+ });
+
+ return toil;
+ }
+
+ protected override Toil FindCarryToCellToil()
+ {
+ Toil toil = base.FindCarryToCellToil();
+
+ // 添加额外条件检查
+ toil.AddFailCondition(() =>
+ {
+ Corpse corpse = TargetThingA as Corpse;
+ Building_CorpseVat vat = TargetThingB as Building_CorpseVat;
+
+ if (corpse == null || corpse.Destroyed || vat == null || vat.Destroyed)
+ {
+ return true;
+ }
+
+ // 检查尸体是否仍然可以被接受
+ AcceptanceReport report = vat.CanAcceptCorpse(corpse);
+ return !report.Accepted;
+ });
+
+ return toil;
+ }
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ // 为尸体和建筑预留
+ if (!pawn.Reserve(TargetA, job, 1, -1, null, errorOnFailed))
+ {
+ return false;
+ }
+ if (!pawn.Reserve(TargetB, job, 1, -1, null, errorOnFailed))
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Jobs/JobDriver_FollowProducer/ThinkNode_ConditionalNotProducedByMechCarrier.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_FollowProducer/ThinkNode_ConditionalNotProducedByMechCarrier.cs
new file mode 100644
index 0000000..73ef1c0
--- /dev/null
+++ b/Source/ArachnaeSwarm/Jobs/JobDriver_FollowProducer/ThinkNode_ConditionalNotProducedByMechCarrier.cs
@@ -0,0 +1,94 @@
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ ///
+ /// 反向条件节点:如果单位不是由生产者生产的,则进入此节点
+ /// 与ThinkNode_ConditionalShouldFollowProducer逻辑相反
+ ///
+ public class ThinkNode_ConditionalNotProducedByMechCarrier : ThinkNode_Conditional
+ {
+ // 可选:是否检查生产者是否存活
+ private bool checkProducerAlive = true;
+
+ // 可选:是否检查生产者是否在同一地图
+ private bool checkSameMap = true;
+
+ // 可选:是否检查生产者是否可到达
+ private bool checkReachable = true;
+
+ // 可选:是否检查生产者类型(pawn必须征召才跟随)
+ private bool checkProducerTypeConditions = true;
+
+ // 可选:额外条件类(可以通过XML添加额外条件)
+ public string extraConditionClass;
+
+ public ThinkNode_ConditionalNotProducedByMechCarrier()
+ {
+ }
+
+ protected override bool Satisfied(Pawn pawn)
+ {
+ // 基础检查:如果不是生产者生产的,返回true
+ bool isProduced = IsProducedByMechCarrier(pawn);
+
+ // 如果是生产者生产的,再检查其他条件
+ if (isProduced)
+ {
+ return false; // 是生产者生产的,不满足条件
+ }
+
+ // 不是生产者生产的,满足条件
+ return true;
+ }
+
+ ///
+ /// 检查pawn是否由生产者生产
+ ///
+ private bool IsProducedByMechCarrier(Pawn pawn)
+ {
+ if (!pawn.Spawned)
+ return false;
+
+ // 检查是否有生产者Comp
+ CompProducedByMechCarrier producerComp = pawn.TryGetComp();
+ if (producerComp == null || !producerComp.HasValidProducer)
+ return false;
+
+ Thing producer = producerComp.Producer;
+ if (producer == null || producer.Destroyed)
+ return false;
+
+ // 检查生产者是否在同一地图
+ if (checkSameMap && producer.Map != pawn.Map)
+ return false;
+
+ // 检查是否可以到达生产者
+ if (checkReachable && !pawn.CanReach(producer, PathEndMode.OnCell, Danger.Deadly))
+ return false;
+
+ // 根据生产者类型检查特定条件
+ if (checkProducerTypeConditions && producer is Pawn pawnProducer)
+ {
+ // 如果生产者是pawn,则只在征召状态下才跟随
+ // 这是为了模拟原版动物跟随主人的逻辑
+ if (checkProducerAlive && (pawnProducer.Dead || pawnProducer.Downed))
+ return false;
+
+ // 只有在征召状态下才认为需要跟随
+ if (!pawnProducer.Drafted)
+ return false;
+ }
+ else if (checkProducerTypeConditions && producer is Building buildingProducer)
+ {
+ // 如果生产者是建筑,默认返回true
+ // 可以根据需要添加其他条件
+ return true;
+ }
+
+ return true;
+ }
+ }
+}