diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 389f4d8..f1fb7c0 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 874a59d..c9159c6 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -271,57 +271,6 @@
-
- ARA_BaseRace_Acid_Launcher
- 酸噬种投射
- 将一只阿拉克涅酸噬种辅虫发射到指定地点,落地后这只寿命有限的辅虫将立刻对敌人展开攻击。
- ArachnaeSwarm/UI/Abilities/ARA_BaseRace_Launcher
- 5000
- true
- 300
- false
- AcidSpray_Warmup
- 3
- true
-
- Verb_CastAbility
- 24
- 1
- AcidSpray_Resolve
- false
-
- true
-
-
-
-
- ArachnaeBase_Race_Acidcut_Proj
-
-
- 饮食
- true
- Food
- 0.2
- 营养值不足,需要进食
-
-
-
-
- ArachnaeBase_Race_Acidcut_Proj
- 阿拉克涅酸噬种
- Projectile_SpawnsPawnZeroAge
-
- ArachnaeSwarm/Things/ARA_Acidcut/Bodies/Naked_Thin
- Graphic_Multi
-
-
- 41
- ArachnaeBase_Race_Acidcut
- true
- ARA_AcidBurn
- 10
-
-
ARA_Toxic_Needle_Fire
毒针连射
diff --git a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
index 4b6f61e..de19d49 100644
--- a/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
+++ b/1.6/1.6/Defs/EvolutionDefs/ARA_Evolution.xml
@@ -381,6 +381,11 @@
-->
+
+ ARA_Fighter_Base_Turret
+ 0
+ true
+
ARA_AcidSprayBurst
@@ -830,7 +835,7 @@
ARA_ShieldHead_Base
坚硬甲壳
- 盾头种虽然身材较小而没有大型阿拉克涅虫族那样的压迫感,但是得益于其覆盖全身的甲壳,防御力可一点不比那些大型虫族弱。它的甲壳被特意设置为会过度生长并脱落,虫族则可以利用其脱落的甲壳作为建设巢穴的工具。一只盾头种每天产出15份甲壳素。
+ 盾头种虽然身材较小而没有大型阿拉克涅虫族那样的压迫感,但是得益于其覆盖全身的甲壳,防御力可一点不比那些大型虫族弱。
HediffWithComps
(0.6, 0.4, 0.8)
false
@@ -1052,7 +1057,7 @@
ARA_ShieldHead_HiveBuilder
亚种-营建种
- 这只阿拉克涅盾头种已经获得拔耀,获得了强大的产出能力和建造能力。一只盾头种每天产出25份甲壳素。
+ 这只阿拉克涅盾头种已经获得拔耀,获得了强大的产出能力和建造能力。一只盾头种每天额外产出15份甲壳素。
HediffWithComps
(0.6, 0.4, 0.8)
false
@@ -1075,7 +1080,7 @@
ARA_Carapace
- 25
+ 15
ARA_Technology_5ESS
-
+
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 376480d..5645ed9 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
@@ -1681,7 +1681,6 @@
SpitterSpawn
- ARA_Technology_5PAV
UnfinishedWeapon
@@ -1974,6 +1973,88 @@
40
+
+ ARA_Fighter_Base_Turret
+ 酸噬蜂巢
+ 阿拉克涅战士种身上的共生器官,会对敌方附近自动投射酸噬种辅虫。
+
+ ArachnaeSwarm/Weapon/ARA_Weapon_Empty
+ Graphic_Single
+
+
+ ARA_Skyraider_Hivelord
+
+
+ 1
+ 1
+ 1
+ 1
+ 0
+
+
+
+ ArachnaeSwarm.Verb_ShootSelfUnderfoot
+ true
+ ArachnaeBase_Race_Acidcut_Proj
+ 18
+ 1
+ 2
+ SpitterSpit
+ GunTail_Medium
+ 9
+ 12
+
+
+
+
+ ARA_Praetorian_Base_Turret
+ 酸噬蜂巢
+ 阿拉克涅禁卫种身上的共生器官,会对敌方附近自动投射酸噬种辅虫。
+
+ ArachnaeSwarm/Weapon/ARA_Weapon_Empty
+ Graphic_Single
+
+
+ ARA_Skyraider_Hivelord
+
+
+ 1
+ 1
+ 1
+ 1
+ 0
+
+
+
+ ArachnaeSwarm.Verb_ShootSelfUnderfoot
+ true
+ ArachnaeBase_Race_Acidcut_Proj
+ 65
+ 1
+ 2
+ SpitterSpit
+ GunTail_Medium
+ 9
+ 2
+
+
+
+
+ ArachnaeBase_Race_Acidcut_Proj
+ 阿拉克涅酸噬种
+ Projectile_SpawnsPawnZeroAge
+
+ ArachnaeSwarm/Things/ARA_Acidcut/Bodies/Naked_Thin
+ Graphic_Multi
+
+
+ 41
+ ArachnaeBase_Race_Acidcut
+ true
+ ARA_AcidBurn
+ 10
+
+
ARA_Skyraider_Hivelord_Turret
食肉蜂巢
diff --git a/1.6/1.6/Defs/Thing_building/ARA_Building.xml b/1.6/1.6/Defs/Thing_building/ARA_Building.xml
index c52f6a8..0930b44 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_Building.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_Building.xml
@@ -10,6 +10,7 @@
TerrainFadeRoughSoftLight
(0.95, 0.95, 0.93, 1)
(240,240,240)
+
(209, 207, 184)
FadeRough
0
@@ -59,6 +60,7 @@
ArachnaeSwarm/Terrain/Surfaces/ARA_InsectCreepTile
Terrain/Surfaces/AncientMegastructure
TerrainFadeRoughSoftLight
+
(0.95, 0.95, 0.93, 1)
(240,240,240)
(209, 207, 184)
@@ -163,29 +165,64 @@
-
+
ARA_SmoothedInsectWall
光滑的阿拉克涅甲壳墙
阿拉克涅工蜂将硬质材料和甲壳素混合堆起来形成的墙壁,虫族对这片墙壁进行了精心打磨,质地坚硬的同时看起来美观多了。
Things/Building/Linked/WallSmooth_MenuIcon
Things/Building/Linked/RockSmooth_Atlas
+ Graphic_Single
+ CutoutComplex
(209, 207, 184)
+
+ (0.7, 0.4, 0.2)
+ (0,0,-0.1)
+
+
+ true
+ 0
- 7
+ 5
1
1000
+ 1500
+ 0
+ 0
- false
+ true
+
+
+ ArachnaeSwarm/Building/Linked/ARA_InsectWall_Blueprint
+
true
false
-
- true
+
+ ARA_InsectDoor
+
- false
- Repair
+ false
+ Heavy
+ EatVegetarian
+ 2
+
+ Metallic
+
+
+ 1
+
+
+
+ Bomb
+ 0.1
+
+
+ Thump
+ 0.1
+
+
ARA_InsectDoor
@@ -329,7 +366,7 @@
1200
0
1000
- 0
+ 1
2
10
@@ -353,7 +390,6 @@
false
Heavy
- ARA_Buildings
true
0
true
@@ -588,7 +624,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -658,7 +694,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -734,7 +770,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -805,7 +841,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -880,7 +916,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -961,7 +997,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -1127,7 +1163,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -1183,7 +1219,7 @@
100
- 15
+ 85
2
0.2
1800
diff --git a/1.6/1.6/Defs/Thing_building/ARA_DropPod.xml b/1.6/1.6/Defs/Thing_building/ARA_DropPod.xml
index cda739c..6727842 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_DropPod.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_DropPod.xml
@@ -48,7 +48,7 @@
100
- 15
+ 85
2
0.2
1800
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 a9f32fe..f304da7 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_NutrientNetworkBuilding.xml
@@ -38,7 +38,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -173,7 +173,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -410,7 +410,7 @@
ARA_JellyVat
生物质酿造池
- 一个阿拉克涅虫族活体组织,可以充分利用活体钜菌的溶解能力,通过消化生物质,来分泌出营养丰富的阿拉克涅虫蜜。
+ 一个阿拉克涅虫族活体组织,可以充分利用活体钜菌的溶解能力,通过消化生物质,来分泌出营养丰富的阿拉克涅虫蜜。阿拉克涅虫蜜会在房间内蔓延,形成蜜池,而生物质酿造池会定期标记这些流淌的蜜浆,命令其他虫族来收集它们。
Building
ArachnaeSwarm/Building/ARA_JellyVat
@@ -464,20 +464,53 @@
ARA_Creep
-
+
+
+ 100
+ 85
+ 2
+ 0.2
+ 1800
+ 0.5
+
+ ArachnaeNode_Race_WeaponSmith
+
+
+
+
+
+ ARA_InsectJelly_Terrain
+ 600
+ true
+ 1
+ 1
+ 10
+ true
+ true
+ false
+ 1
+
+
+ true
+ 600
+ 10
+ 0
+
+
+
+
+ true
+
+ AcidSpray_Resolve
+ AcidSpray_Resolve
+
Biomass
生物质
@@ -499,50 +532,42 @@
true
false
-
- 200
- 0.25
- 2000
- 1
-
-
-
- 虫蜜
- 虫蜜
-
- 25
- 0
- true
-
-
-
- ARA_InsectJelly
-
-
-
- false
- false
- false
- false
- false
- true
-
-
-
-
- 60
- 0.99
- true
- true
- false
-
-
-
- ARA_InsectCreep
- 6
-
+
+ ARA_InsectJelly_Terrain
+ 阿拉克涅虫蜜
+ 250
+ ArachnaeSwarm/Terrain/Surfaces/ARA_InsectJelly_Terrain
+ ARA_InsectCreep
+ (231, 224, 188)
+ Terrain/Surfaces/AncientMegastructure
+ TerrainFadeRoughSoftLight
+
+ 85
+ 0.22
+
+
+ 2
+
+ true
+ Freshwater
+ Map/WaterDepth
+ 100
+ Water
+ Misc
+ 390
+ false
+ 1
+ false
+ 600
+
+ false
+
+ None
+
+
ARA_Carapace_Productor
骨花
@@ -601,39 +626,109 @@
-
-
- Steels
- 钢铁
- 钢铁
-
-
- Steel
-
-
- 50
- 50
- true
-
- true
- true
+
+
+ ARA_Carapace_Column
+ 1
+ 1200
+ 10
+ false
+ false
+
+
+
+
+
+
+ true
+
+ PowerOnSmall
+ DropPod_Leaving
+ ResearchComplete
+
+
+ true
+ true
+
+
+ true
+ 1200
+ 10
+ 0
+
+
+
+
+ true
-
-
- 60000~60000
-
-
- ARA_Carapace
- 25
-
-
- true
-
-
-
- ARA_InsectCreep
- 6
+
+
+ 100
+ 85
+ 2
+ 0.2
+ 1800
+ 0.5
+
+ ArachnaeNode_Race_WeaponSmith
+
+
+ ARA_Carapace_Column
+ 骨柱
+ 阿拉克涅的骨花通过催化尸体而转变得到的柱子,。
+ 2040
+ Building
+ PassThroughOnly
+ 0.25
+ 0
+ 0.8
+
+ (1.25,1.25)
+ (0,0,0.2)
+ ArachnaeSwarm/Building/ARA_Column
+ Graphic_Single
+ CutoutComplex
+
+ (0.3, 0.5, 0.3)
+ (0,0,-0.23)
+
+
+ (0.2,0.2,0.6,0.6)
+
+
+
+ 20
+ 750
+ 10
+ 0
+ 0
+
+ 0
+
+
+ 20
+
+ true
+ false
+ false
+ 0
+
+ true
+ false
+ true
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml b/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
index 68cf541..6554f2e 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_Ootheca.xml
@@ -56,7 +56,7 @@
- 1
+ 3
@@ -145,13 +145,17 @@
ArachnaeSwarm.ITab_Ootheca_Incubation
+
+ 25
+
+
ArachnaeSwarm.PlaceWorker_CustomRadius
100
- 15
+ 85
2
0.2
1800
@@ -175,7 +179,7 @@
孵化···
选择孵化的阿拉克涅督虫···
孵化菜单
- UI/Commands/IncubatorSwitch
+ ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon
@@ -220,7 +224,6 @@
ArachnaeNode_Race_ShieldHead
2
- UI/Buttons/IncubateUnitA
ARA_Incubator_1_Reward_Hediffs
ARA_Incubator_2_Reward_Hediffs
@@ -235,7 +238,6 @@
ArachnaeNode_Race_WeaponSmith
2
- UI/Buttons/IncubateUnitA
ARA_Incubator_1_Reward_Hediffs
ARA_Incubator_2_Reward_Hediffs
@@ -250,7 +252,6 @@
ArachnaeNode_Race_Fighter
2
- UI/Buttons/IncubateUnitA
ARA_Technology_1KYC
ARA_Incubator_1_Reward_Hediffs
@@ -266,7 +267,6 @@
ArachnaeNode_Race_Myrmecocystus
3
- UI/Buttons/IncubateUnitA
ARA_Incubator_1_Reward_Hediffs
ARA_Incubator_2_Reward_Hediffs
@@ -281,7 +281,6 @@
ArachnaeNode_Race_Facehugger
2
- UI/Buttons/IncubateUnitA
ARA_Technology_4KYC
ARA_Incubator_1_Reward_Hediffs
@@ -297,7 +296,6 @@
ARA_MimicNematodeShamblerSwarmer
1
- UI/Buttons/IncubateUnitA
ARA_Technology_6MEN
ARA_Incubator_1_Reward_Hediffs
@@ -313,7 +311,6 @@
ArachnaeNode_Race_Smokepop
6
- UI/Buttons/IncubateUnitA
ARA_Technology_5KYC
ARA_Incubator_1_Reward_Hediffs
@@ -329,7 +326,6 @@
ArachnaeNode_Race_NeuroSwarm
10
- UI/Buttons/IncubateUnitA
ARA_Technology_6KYC
ARA_Incubator_1_Reward_Hediffs
@@ -345,7 +341,6 @@
ArachnaeNode_Race_Skyraider
6
- UI/Buttons/IncubateUnitA
ARA_Technology_2KYC
ARA_Incubator_1_Reward_Hediffs
@@ -361,7 +356,6 @@
ArachnaeNode_Race_Praetorian
12
- UI/Buttons/IncubateUnitA
ARA_Technology_7KYC
ARA_Incubator_1_Reward_Hediffs
@@ -384,8 +378,8 @@
(113,141,117,0)
- -10
- 20
+ 6
+ 36
0.015
@@ -465,6 +459,10 @@
+
+ 25
+
+
ArachnaeSwarm.ITab_EquipmentOotheca_Incubation
@@ -476,7 +474,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -505,8 +503,8 @@
(113,141,117,0)
- -10
- 20
+ 6
+ 36
0.015
@@ -527,11 +525,13 @@
(1,1)
+ ARA_Buildings
Building
PassThroughOnly
0.3
false
Normal
+ ARA_Incubator_Nutrient_Solution
2000
50
@@ -545,6 +545,10 @@
ARA_Gene_Essence
+
+ 25
+
+
@@ -576,12 +580,23 @@
30
- -30
- 55
+ 6
+ 36
0.00005
0.005
0.001
+
+ 100
+ 85
+ 2
+ 0.2
+ 1800
+ 0.5
+
+ ArachnaeNode_Race_WeaponSmith
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml b/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml
index 8bc3562..3637a3d 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml
@@ -65,7 +65,7 @@
100
- 15
+ 85
2
0.2
1800
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 f92e1cd..44d6476 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_SwarmTurret.xml
@@ -290,7 +290,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -439,7 +439,7 @@
100
- 15
+ 85
2
0.2
1800
@@ -611,7 +611,7 @@
100
- 15
+ 85
2
0.2
1800
diff --git a/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml b/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
index 61a4ee9..ffbad6b 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
@@ -41,7 +41,7 @@
100
- 15
+ 85
2
0.2
1800
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_CorpseConverter.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_CorpseConverter.xml
new file mode 100644
index 0000000..c91a8dd
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_CorpseConverter.xml
@@ -0,0 +1,39 @@
+
+
+
+ 生物质不足,无法进行尸体转换
+ 生物质不足,无法标记拆除
+ 已创建尸体储存区,包含{0}个单元格
+ 自动标记拆除功能已启用
+ 自动标记拆除功能已禁用
+
+
+ 电力:{0}
+ 生物质:{0} / {1}
+ 每次转换消耗生物质:{0}
+ 未找到生物质组件!
+
+ 工作中:{0}
+ 目标尸体:{0}
+ 下次转换:{0}天后
+
+ 转换半径:{0}格
+
+
+ 创建尸体储存区
+ 在转换器范围内创建尸体储存区,便于集中尸体进行转换
+ 切换自动标记
+ 启用或禁用自动标记拆除功能。启用后,设备会定期标记范围内的目标建筑为拆除。
+
+
+ DEV: Test Conversion
+ DEV: Reset Timer
+ DEV: Test Marking
+
+
+ 未找到有效尸体
+ 未找到有效建筑
+
+
+ 尸体转换区
+
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_TerrainChanger.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_TerrainChanger.xml
new file mode 100644
index 0000000..cc117e0
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/ARA_TerrainChanger.xml
@@ -0,0 +1,36 @@
+
+
+
+ 生物质不足,无法生成地形
+ 生物质不足,无法标记拆除
+ 自动标记拆除功能已启用
+ 自动标记拆除功能已禁用
+
+
+ 切换自动标记
+ 启用或禁用自动标记拆除功能。启用后,该结构会定期呼叫附近的虫族收集分泌物。
+
+
+ 电力:{0}
+ 生物质:{0} / {1}
+ 每次转换消耗生物质:{0}
+ 每次标记消耗生物质:{0}
+ 未找到生物质组件!
+
+ 工作中:{0}
+ 目标位置:{0}
+ 下次分泌:{0}天后
+
+ 目标地形:{0}
+ 分泌半径:{0}格
+
+ 自动标记:{0}
+ 下次标记:{0}天后
+ 标记中:{0}
+ 标记目标:{0}
+ 标记半径:{0}格
+
+
+ 已启用
+ 已禁用
+
diff --git a/Content/Textures/ArachnaeSwarm/Terrain/Surfaces/ARA_InsectJelly_Terrain.png b/Content/Textures/ArachnaeSwarm/Terrain/Surfaces/ARA_InsectJelly_Terrain.png
new file mode 100644
index 0000000..51ee441
Binary files /dev/null and b/Content/Textures/ArachnaeSwarm/Terrain/Surfaces/ARA_InsectJelly_Terrain.png differ
diff --git a/Content/Textures/ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon.png b/Content/Textures/ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon.png
new file mode 100644
index 0000000..74e3976
Binary files /dev/null and b/Content/Textures/ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon.png differ
diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo
index 06a7edd..9cae529 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 1ef1ca3..cb49570 100644
--- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
+++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json
@@ -1,25 +1,81 @@
{
"Version": 1,
- "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
+ "WorkspaceRootPath": "E:\\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\\building_comps\\ara_productstorage\\compproperties_productstorage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_productstorage\\compproperties_productstorage.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\\jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\compproperties_incubatordata.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\\jobs\\jobdriver_stripchitin\\compproperties_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\compproperties_chitinstripping.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\\building_comps\\ara_building_refuelingvat\\building_refuelingvat.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\\jobs\\jobdriver_stripchitin\\comp_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\comp_chitinstripping.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\\verbs\\verb_shootselfunderfoot.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:verbs\\verb_shootselfunderfoot.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_hediffcomp_topturret\\hediffcomp_topturret.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffcomp_topturret\\hediffcomp_topturret.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\\roomrole\\roomroleworker_incubator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:roomrole\\roomroleworker_incubator.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\\building_comps\\ara_compinteractiveproducer\\compresearchproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_compinteractiveproducer\\compresearchproducer.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\\ara_hediffdefof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:ara_hediffdefof.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\\building_comps\\ara_corpseconverter\\compcorpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_corpseconverter\\compcorpseconverter.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\\building_comps\\ara_corpseconverter\\compproperties_corpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_corpseconverter\\compproperties_corpseconverter.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\\building_comps\\ara_terrainchanger\\compterrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_terrainchanger\\compterrainchanger.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\\building_comps\\ara_terrainchanger\\compproperties_terrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_terrainchanger\\compproperties_terrainchanger.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\\building_comps\\wula_mutifuelspawner\\comprefuelablenutrition_withkey.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\wula_mutifuelspawner\\comprefuelablenutrition_withkey.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\\building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_building_refuelingvat\\building_refuelingvat.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_ootheca\\itab_ootheca_incubation.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\itab_ootheca_incubation.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\\buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\compproperties_incubatordata.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_equipmentootheca\\building_equipmentootheca.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\\buildings\\building_ootheca\\oothecaincubatorextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\oothecaincubatorextension.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\\buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_equipmentootheca\\compproperties_equipmentincubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\compproperties_equipmentincubatordata.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\\buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
@@ -30,76 +86,245 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 0,
+ "SelectedChildIndex": 1,
"Children": [
- {
- "$type": "Document",
- "DocumentIndex": 0,
- "Title": "CompProperties_ProductStorage.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
- "RelativeDocumentMoniker": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
- "RelativeToolTip": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABQAAAAMAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-16T08:35:48.647Z",
- "EditorCaption": ""
- },
- {
- "$type": "Document",
- "DocumentIndex": 1,
- "Title": "CompProperties_IncubatorData.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
- "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
- "RelativeToolTip": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
- "ViewState": "AgIAAP4AAAAAAAAAAAAWwAIBAABCAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-16T08:17:40.867Z",
- "EditorCaption": ""
- },
- {
- "$type": "Document",
- "DocumentIndex": 3,
- "Title": "ITab_Ootheca_Incubation.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
- "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
- "RelativeToolTip": "Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
- "ViewState": "AgIAAJUAAAAAAAAAAAAewMkAAAANAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-16T08:14:08.752Z",
- "EditorCaption": ""
- },
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
- "DocumentIndex": 4,
- "Title": "Building_EquipmentOotheca.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
- "RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
- "RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
- "ViewState": "AgIAALgCAAAAAAAAAAAAAMQCAAAjAAAAAAAAAA==",
+ "DocumentIndex": 0,
+ "Title": "JobDriver_StripChitin.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
+ "RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs*",
+ "RelativeToolTip": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs*",
+ "ViewState": "AgIAAFcAAAAAAAAAAAAAAHMAAAAoAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-16T08:13:46.678Z",
+ "WhenOpened": "2025-12-16T15:50:38.09Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "CompProperties_ChitinStripping.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
+ "RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
+ "RelativeToolTip": "Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAAAtAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T15:50:04.277Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
- "Title": "Building_RefuelingVat.cs",
- "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
- "RelativeDocumentMoniker": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
- "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
- "RelativeToolTip": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
- "ViewState": "AgIAAP4AAAAAAAAAAAAewA8BAAAAAAAAAAAAAA==",
+ "Title": "Comp_ChitinStripping.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
+ "RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
+ "RelativeToolTip": "Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAABWAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2025-12-16T04:00:20.165Z",
+ "WhenOpened": "2025-12-16T15:49:51.675Z",
"EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "Verb_ShootSelfUnderfoot.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Verbs\\Verb_ShootSelfUnderfoot.cs",
+ "RelativeDocumentMoniker": "Verbs\\Verb_ShootSelfUnderfoot.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Verbs\\Verb_ShootSelfUnderfoot.cs",
+ "RelativeToolTip": "Verbs\\Verb_ShootSelfUnderfoot.cs",
+ "ViewState": "AgIAAJAAAAAAAAAAAAAcwJwAAAAoAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T15:07:22.127Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 4,
+ "Title": "HediffComp_TopTurret.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
+ "RelativeDocumentMoniker": "Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
+ "RelativeToolTip": "Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
+ "ViewState": "AgIAACcBAAAAAAAAAAAkwD0BAAAjAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T14:52:46.325Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 5,
+ "Title": "RoomRoleWorker_Incubator.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\RoomRole\\RoomRoleWorker_Incubator.cs",
+ "RelativeDocumentMoniker": "RoomRole\\RoomRoleWorker_Incubator.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\RoomRole\\RoomRoleWorker_Incubator.cs",
+ "RelativeToolTip": "RoomRole\\RoomRoleWorker_Incubator.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAABsAAAARAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T14:32:31.389Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 6,
+ "Title": "CompResearchProducer.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAADwvy0AAAAAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T14:29:05.969Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 8,
+ "Title": "CompCorpseConverter.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
+ "ViewState": "AgIAABwDAAAAAAAAAAAIwCoDAAARAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T12:23:40.696Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 7,
+ "Title": "ARA_HediffDefOf.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_HediffDefOf.cs",
+ "RelativeDocumentMoniker": "ARA_HediffDefOf.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_HediffDefOf.cs",
+ "RelativeToolTip": "ARA_HediffDefOf.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAADwvy0AAAAJAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-15T17:32:18.493Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 9,
+ "Title": "CompProperties_CorpseConverter.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T12:23:39.636Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 12,
+ "Title": "CompRefuelableNutrition_WithKey.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
+ "RelativeToolTip": "Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAACUAAABAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T10:38:33.135Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 10,
+ "Title": "CompTerrainChanger.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
+ "ViewState": "AgIAAK0CAAAAAAAAAAAcwPYCAAAMAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T10:30:16.921Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 11,
+ "Title": "CompProperties_TerrainChanger.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T10:30:15.601Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 13,
+ "Title": "Building_RefuelingVat.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
+ "RelativeDocumentMoniker": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
+ "RelativeToolTip": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T10:28:54.756Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 14,
+ "Title": "CompProperties_IncubatorData.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
+ "RelativeToolTip": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
+ "ViewState": "AgIAANcAAAAAAAAAAIA1wPoAAAAxAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T04:37:03.042Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 15,
+ "Title": "OothecaIncubatorExtension.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
+ "RelativeToolTip": "Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAADwvxUAAABBAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-16T04:36:59.394Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 18,
+ "Title": "Building_EquipmentOotheca.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
+ "RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
+ "ViewState": "AgIAACcAAAAAAAAAAAAAADoDAABSAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-15T18:22:14.171Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 16,
+ "Title": "Building_Ootheca.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
+ "RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
+ "ViewState": "AgIAALcCAAAAAAAAAAAewNgCAAAVAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-15T18:22:12.217Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 17,
+ "Title": "CompProperties_EquipmentIncubatorData.cs",
+ "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
+ "RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
+ "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
+ "RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
+ "ViewState": "AgIAAA4AAAAAAAAAAADwvyYAAAAaAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2025-12-15T17:55:40.041Z"
}
]
}
diff --git a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
index 7620d1e..1034789 100644
--- a/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
+++ b/Source/ArachnaeSwarm/ARA_HediffDefOf.cs
@@ -37,4 +37,14 @@ namespace ArachnaeSwarm
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_EffecterDefOf));
}
}
+ [DefOf]
+ public static class ARA_SoundDefOf
+ {
+ public static SoundDef AcidSpray_Resolve;
+
+ static ARA_SoundDefOf()
+ {
+ DefOfHelper.EnsureInitializedInCtor(typeof(ARA_SoundDefOf));
+ }
+ }
}
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index e1f2062..d904c86 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -124,13 +124,15 @@
-
+
+
+
@@ -138,6 +140,8 @@
+
+
@@ -195,6 +199,7 @@
+
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs
index ef697f2..d5ea650 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_Building_RefuelingVat/Building_RefuelingVat.cs
@@ -138,7 +138,7 @@ namespace ArachnaeSwarm
if (!Destroyed)
{
// 销毁建筑
- Destroy(DestroyMode.Vanish);
+ Kill();
}
}
@@ -272,7 +272,7 @@ namespace ArachnaeSwarm
DamageInfo acidDamage = new DamageInfo(
acidDamageDef,
- 1000f, // 每次1.5点伤害
+ 1.5f, // 每次1.5点伤害
2f, // 护甲穿透
-1f, // 随机角度
null, // 将建筑设为伤害来源
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompCorpseConverter.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompCorpseConverter.cs
new file mode 100644
index 0000000..0ad5f1b
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompCorpseConverter.cs
@@ -0,0 +1,967 @@
+// File: Comps/CompCorpseConverter.cs
+using RimWorld;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+using Verse.Sound;
+using System.Text;
+using System.Linq;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class CompCorpseConverter : ThingComp
+ {
+ // 属性引用
+ private CompProperties_CorpseConverter Props => (CompProperties_CorpseConverter)props;
+
+ // 状态变量
+ private int ticksUntilNextConversion;
+ private bool isWorking = false;
+ private int workTicksRemaining = 0;
+ private Corpse targetCorpse = null;
+ private Effecter effecter;
+ private Effecter conversionEffecter;
+
+ // --- 新增:自动标记拆除状态 ---
+ private bool autoMarkForDeconstructionEnabled = true;
+ private int ticksUntilNextMarkDeconstruction;
+ private bool isMarking = false;
+ private int markingTicksRemaining = 0;
+ private Thing markingTargetBuilding = null;
+ private Effecter markingEffecter;
+
+ // 当前工作速度乘数
+ private float currentWorkSpeedMultiplier = 1.0f;
+
+ // 缓存燃料组件
+ private CompRefuelableNutrition_WithKey compRefuelable;
+ private bool refuelableComponentCached = false;
+
+ // 储存区图标缓存
+ private static readonly CachedTexture CreateCorpseStockpileIcon = new CachedTexture("UI/Icons/CorpseStockpileZone");
+
+ // 临时列表
+ private List tmpRadialCells = new List();
+
+ // 获取径向单元格(转换半径内)
+ private IEnumerable RadialCells => GenRadial.RadialCellsAround(parent.Position, Props.conversionRadius, useCenter: true);
+
+ // 获取燃料组件
+ private CompRefuelableNutrition_WithKey CompRefuelable
+ {
+ get
+ {
+ if (!refuelableComponentCached)
+ {
+ compRefuelable = parent.TryGetComp();
+ refuelableComponentCached = true;
+ }
+ return compRefuelable;
+ }
+ }
+
+ // 检查燃料是否充足
+ private bool HasSufficientFuel
+ {
+ get
+ {
+ if (!Props.requiresFuel)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ return CompRefuelable.Fuel >= Props.minFuelToOperate;
+ }
+ }
+
+ // 检查是否有足够的燃料用于标记
+ private bool HasSufficientFuelForMarking
+ {
+ get
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ return CompRefuelable.Fuel >= Props.fuelConsumptionPerMark;
+ }
+ }
+
+ // 消耗燃料
+ private bool ConsumeFuelIfNeeded()
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerConversion <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ if (CompRefuelable.Fuel >= Props.fuelConsumptionPerConversion)
+ {
+ CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerConversion);
+ return true;
+ }
+
+ return false;
+ }
+
+ // 消耗标记燃料
+ private bool ConsumeMarkingFuelIfNeeded()
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ if (CompRefuelable.Fuel >= Props.fuelConsumptionPerMark)
+ {
+ CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerMark);
+ return true;
+ }
+
+ return false;
+ }
+
+ // 获取电源状态
+ private bool HasPower
+ {
+ get
+ {
+ if (!Props.requiresPower)
+ return true;
+
+ var compPower = parent.TryGetComp();
+ return compPower != null && compPower.PowerOn;
+ }
+ }
+
+ // 获取房间
+ private Room GetRoom()
+ {
+ var map = parent.Map;
+ if (map == null)
+ return null;
+
+ return parent.Position.GetRoom(map);
+ }
+
+ // 检查是否满足操作条件
+ private bool CanOperate()
+ {
+ // 检查是否有电
+ if (Props.requiresPower && !HasPower)
+ return false;
+
+ // 检查是否有足够的燃料
+ if (Props.requiresFuel && !HasSufficientFuel)
+ return false;
+
+ // 检查是否在房间内(如果需要)
+ if (Props.requiresRoom)
+ {
+ var room = GetRoom();
+ if (room == null || !room.ProperRoom)
+ return false;
+
+ // 检查房间评分
+ if (room.GetStat(RoomStatDefOf.Impressiveness) < Props.minRoomScore)
+ return false;
+ }
+
+ return true;
+ }
+
+ // 检查是否可以执行标记操作
+ private bool CanMarkForDeconstruction()
+ {
+ if (!Props.enableAutoMarkForDeconstruction || !autoMarkForDeconstructionEnabled)
+ return false;
+
+ if (!CanOperate())
+ return false;
+
+ // 检查标记燃料
+ if (Props.requiresFuel && !HasSufficientFuelForMarking)
+ return false;
+
+ return true;
+ }
+
+ // 获取有效的目标尸体
+ private bool TryGetValidTargetCorpse(out Corpse result)
+ {
+ result = null;
+ var map = parent.Map;
+ if (map == null)
+ return false;
+
+ // 获取搜索范围
+ var center = parent.Position;
+ int radius = Mathf.CeilToInt(Props.conversionRadius);
+
+ // 获取房间(如果需要)
+ Room parentRoom = null;
+ if (Props.requiresRoom)
+ {
+ parentRoom = GetRoom();
+ if (parentRoom == null)
+ return false;
+ }
+
+ // 收集所有候选尸体
+ List candidateCorpses = new List();
+
+ for (int x = -radius; x <= radius; x++)
+ {
+ for (int z = -radius; z <= radius; z++)
+ {
+ IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
+
+ if (!cell.InBounds(map))
+ continue;
+
+ // 检查距离
+ float distance = cell.DistanceTo(center);
+ if (distance > Props.conversionRadius)
+ continue;
+
+ // 检查房间(如果需要)
+ if (Props.requiresRoom)
+ {
+ var cellRoom = cell.GetRoom(map);
+ if (cellRoom == null || cellRoom != parentRoom)
+ continue;
+ }
+
+ // 获取单元格中的所有东西
+ var things = cell.GetThingList(map);
+ foreach (var thing in things)
+ {
+ if (thing is Corpse corpse)
+ {
+ // 检查尸体是否腐烂
+ if (corpse.GetRotStage() == RotStage.Fresh || corpse.GetRotStage() == RotStage.Rotting)
+ {
+ // 检查是否在可接受尸体列表中(如果有定义)
+ if (Props.acceptedCorpseDefs != null && Props.acceptedCorpseDefs.Count > 0)
+ {
+ if (!Props.acceptedCorpseDefs.Contains(corpse.def))
+ continue;
+ }
+
+ // 排除机械族尸体(如果启用)
+ if (Props.excludeMechanoidCorpses)
+ {
+ var pawn = corpse.InnerPawn;
+ if (pawn != null && pawn.RaceProps.IsMechanoid)
+ {
+ continue; // 跳过机械族尸体
+ }
+ }
+
+ candidateCorpses.Add(corpse);
+ }
+ }
+ }
+ }
+ }
+
+ if (candidateCorpses.Count == 0)
+ return false;
+
+ // 选择最近的尸体
+ float closestDistance = float.MaxValue;
+ Corpse closestCorpse = null;
+
+ foreach (var corpse in candidateCorpses)
+ {
+ float distance = corpse.Position.DistanceTo(center);
+ if (distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestCorpse = corpse;
+ }
+ }
+
+ if (closestCorpse != null)
+ {
+ result = closestCorpse;
+ return true;
+ }
+
+ return false;
+ }
+
+ // 获取有效的标记拆除建筑
+ private bool TryGetValidMarkingBuilding(out Thing result)
+ {
+ result = null;
+ var map = parent.Map;
+ if (map == null)
+ return false;
+
+ // 获取搜索范围
+ var center = parent.Position;
+ int radius = Mathf.CeilToInt(Props.markDeconstructionRadius);
+
+ // 获取房间(如果需要)
+ Room parentRoom = null;
+ if (Props.requiresRoom)
+ {
+ parentRoom = GetRoom();
+ if (parentRoom == null)
+ return false;
+ }
+
+ // 收集所有候选建筑
+ List candidateBuildings = new List();
+
+ for (int x = -radius; x <= radius; x++)
+ {
+ for (int z = -radius; z <= radius; z++)
+ {
+ IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
+
+ if (!cell.InBounds(map))
+ continue;
+
+ // 检查距离
+ float distance = cell.DistanceTo(center);
+ if (distance > Props.markDeconstructionRadius)
+ continue;
+
+ // 检查房间(如果需要)
+ if (Props.requiresRoom)
+ {
+ var cellRoom = cell.GetRoom(map);
+ if (cellRoom == null || cellRoom != parentRoom)
+ continue;
+ }
+
+ // 获取单元格中的所有东西
+ var things = cell.GetThingList(map);
+ foreach (var thing in things)
+ {
+ // 检查是否是目标建筑
+ if (thing.def == Props.targetThingDef)
+ {
+ // 检查是否已经标记了拆除
+ if (map.designationManager.DesignationOn(thing, DesignationDefOf.Deconstruct) != null)
+ continue;
+
+ candidateBuildings.Add(thing);
+ }
+ }
+ }
+ }
+
+ if (candidateBuildings.Count == 0)
+ return false;
+
+ // 选择最近的建筑
+ float closestDistance = float.MaxValue;
+ Thing closestBuilding = null;
+
+ foreach (var building in candidateBuildings)
+ {
+ float distance = building.Position.DistanceTo(center);
+ if (distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestBuilding = building;
+ }
+ }
+
+ if (closestBuilding != null)
+ {
+ result = closestBuilding;
+ return true;
+ }
+
+ return false;
+ }
+
+ // 开始工作
+ private void StartWorking(Corpse targetCorpse)
+ {
+ this.targetCorpse = targetCorpse;
+ this.isWorking = true;
+
+ // 计算工作时间(基于距离)
+ float distance = targetCorpse.Position.DistanceTo(parent.Position);
+ float workTimeFactor = 1f + (distance / Props.conversionRadius) * 0.5f; // 距离越远,时间越长
+
+ int baseWorkTime = Mathf.RoundToInt(Props.conversionInterval * 0.1f); // 工作时间为间隔的10%
+ workTicksRemaining = Mathf.RoundToInt(baseWorkTime * workTimeFactor / currentWorkSpeedMultiplier);
+
+ // 播放声音
+ if (Props.workingSound != null)
+ {
+ Props.workingSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
+ }
+
+ // 启动工作效果器
+ if (Props.showVisualEffects && Props.workingEffecter != null)
+ {
+ effecter = Props.workingEffecter.Spawn();
+ effecter.Trigger(parent, targetCorpse);
+ }
+
+ // 启动转换效果器(在尸体上)
+ if (Props.showVisualEffects && Props.conversionEffecter != null)
+ {
+ conversionEffecter = Props.conversionEffecter.Spawn();
+ conversionEffecter.Trigger(targetCorpse, parent);
+ }
+ }
+
+ // 开始标记工作
+ private void StartMarking(Thing targetBuilding)
+ {
+ this.markingTargetBuilding = targetBuilding;
+ this.isMarking = true;
+
+ // 计算标记时间(基于距离)
+ float distance = targetBuilding.Position.DistanceTo(parent.Position);
+ float workTimeFactor = 1f + (distance / Props.markDeconstructionRadius) * 0.5f;
+
+ int baseMarkTime = Mathf.RoundToInt(Props.markDeconstructionInterval * 0.05f); // 标记时间为间隔的5%
+ markingTicksRemaining = Mathf.RoundToInt(baseMarkTime * workTimeFactor / currentWorkSpeedMultiplier);
+
+ // 播放标记声音
+ if (Props.markSound != null)
+ {
+ Props.markSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
+ }
+ }
+
+ // 完成转换
+ private void CompleteConversion()
+ {
+ var map = parent.Map;
+ if (map == null || targetCorpse == null || targetCorpse.Destroyed || !targetCorpse.Spawned)
+ {
+ ResetWorkState();
+ return;
+ }
+
+ // 检查并消耗燃料
+ if (!ConsumeFuelIfNeeded())
+ {
+ Messages.Message("ARA_CorpseConverter.InsufficientFuel".Translate(),
+ new TargetInfo(targetCorpse.Position, map), MessageTypeDefOf.NegativeEvent);
+ ResetWorkState();
+ return;
+ }
+
+ // 记录尸体的位置和信息
+ IntVec3 corpsePosition = targetCorpse.Position;
+ string corpseName = targetCorpse.InnerPawn?.LabelShort ?? "unknown";
+
+ // 移除尸体
+ targetCorpse.Destroy(DestroyMode.Vanish);
+
+ // 播放转换声音
+ if (Props.conversionSound != null)
+ {
+ Props.conversionSound.PlayOneShot(new TargetInfo(corpsePosition, map));
+ }
+
+ // 生成目标建筑
+ if (Props.targetThingDef != null)
+ {
+ Thing convertedThing = ThingMaker.MakeThing(Props.targetThingDef);
+
+ // 检查是否是建筑
+ if (convertedThing.def.category == ThingCategory.Building)
+ {
+ // 尝试在尸体原位置生成
+ GenSpawn.Spawn(convertedThing, corpsePosition, map);
+
+ // 播放完成声音
+ if (Props.completionSound != null)
+ {
+ Props.completionSound.PlayOneShot(new TargetInfo(corpsePosition, map));
+ }
+
+ // 显示消息(仅开发模式)
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CorpseConverter] Converted {corpseName} at {corpsePosition} to {convertedThing.LabelCap}");
+ }
+ }
+ else
+ {
+ Log.Error($"CorpseConverter: targetThingDef {Props.targetThingDef.defName} is not a building! Cannot spawn.");
+ }
+ }
+
+ ResetWorkState();
+ }
+
+ // 完成标记工作
+ private void CompleteMarking()
+ {
+ var map = parent.Map;
+ if (map == null || markingTargetBuilding == null || markingTargetBuilding.Destroyed || !markingTargetBuilding.Spawned)
+ {
+ ResetMarkingState();
+ return;
+ }
+
+ // 检查并消耗标记燃料
+ if (!ConsumeMarkingFuelIfNeeded())
+ {
+ Messages.Message("ARA_CorpseConverter.InsufficientFuelForMarking".Translate(),
+ new TargetInfo(markingTargetBuilding.Position, map), MessageTypeDefOf.NegativeEvent);
+ ResetMarkingState();
+ return;
+ }
+
+ // 确保是目标建筑(安全检查)
+ if (markingTargetBuilding.def != Props.targetThingDef)
+ {
+ ResetMarkingState();
+ return;
+ }
+
+ // 添加拆除标记
+ map.designationManager.AddDesignation(new Designation(markingTargetBuilding, DesignationDefOf.Deconstruct));
+
+ // 播放完成声音
+ if (Props.markCompleteSound != null)
+ {
+ Props.markCompleteSound.PlayOneShot(new TargetInfo(markingTargetBuilding.Position, map));
+ }
+
+ // 显示消息(仅开发模式)
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[CorpseConverter] Marked building at {markingTargetBuilding.Position} ({markingTargetBuilding.LabelCap}) for deconstruction");
+ }
+
+ ResetMarkingState();
+ }
+
+ // 重置工作状态
+ private void ResetWorkState()
+ {
+ isWorking = false;
+ workTicksRemaining = 0;
+ targetCorpse = null;
+
+ // 清理效果器
+ if (effecter != null)
+ {
+ effecter.Cleanup();
+ effecter = null;
+ }
+
+ if (conversionEffecter != null)
+ {
+ conversionEffecter.Cleanup();
+ conversionEffecter = null;
+ }
+ }
+
+ // 重置标记状态
+ private void ResetMarkingState()
+ {
+ isMarking = false;
+ markingTicksRemaining = 0;
+ markingTargetBuilding = null;
+
+ // 清理标记效果器
+ if (markingEffecter != null)
+ {
+ markingEffecter.Cleanup();
+ markingEffecter = null;
+ }
+ }
+
+ // 更新工作速度
+ private void UpdateWorkSpeed()
+ {
+ float multiplier = 1.0f;
+
+ if (Props.requiresPower && HasPower)
+ {
+ multiplier *= Props.poweredWorkSpeedMultiplier;
+ }
+
+ if (Props.requiresFuel && HasSufficientFuel)
+ {
+ // 燃料充足时可能有额外的速度加成
+ }
+
+ currentWorkSpeedMultiplier = multiplier;
+ }
+
+ // Tick更新
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ // --- 处理尸体转换 ---
+ if (isWorking)
+ {
+ workTicksRemaining--;
+
+ if (workTicksRemaining <= 0)
+ {
+ CompleteConversion();
+ }
+
+ // 更新效果器
+ if (effecter != null)
+ {
+ effecter.EffectTick(parent, targetCorpse);
+ }
+
+ if (conversionEffecter != null)
+ {
+ conversionEffecter.EffectTick(targetCorpse, parent);
+ }
+ }
+ else if (CanOperate())
+ {
+ UpdateWorkSpeed();
+
+ // 等待下一次转换
+ if (ticksUntilNextConversion <= 0)
+ {
+ // 尝试找到有效目标尸体
+ if (TryGetValidTargetCorpse(out Corpse target))
+ {
+ // 在开始工作前再次检查燃料
+ if (Props.requiresFuel && Props.fuelConsumptionPerConversion > 0)
+ {
+ if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerConversion)
+ {
+ // 燃料不足,重置计时器但跳过这次工作
+ ticksUntilNextConversion = Mathf.RoundToInt(Props.conversionInterval / currentWorkSpeedMultiplier);
+ return;
+ }
+ }
+
+ StartWorking(target);
+ }
+
+ // 重置计时器,无论是否成功找到目标
+ ticksUntilNextConversion = Mathf.RoundToInt(Props.conversionInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ ticksUntilNextConversion--;
+ }
+ }
+ else
+ {
+ if (isWorking)
+ {
+ ResetWorkState();
+ }
+ }
+
+ // --- 处理自动标记拆除 ---
+ if (isMarking)
+ {
+ markingTicksRemaining--;
+
+ if (markingTicksRemaining <= 0)
+ {
+ CompleteMarking();
+ }
+
+ // 更新标记效果器
+ if (markingEffecter != null)
+ {
+ markingEffecter.EffectTick(parent, markingTargetBuilding);
+ }
+ }
+ else if (CanMarkForDeconstruction())
+ {
+ // 等待下一次标记
+ if (ticksUntilNextMarkDeconstruction <= 0)
+ {
+ // 尝试找到有效标记建筑
+ if (TryGetValidMarkingBuilding(out Thing target))
+ {
+ // 在开始标记前再次检查燃料
+ if (Props.requiresFuel && Props.fuelConsumptionPerMark > 0)
+ {
+ if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerMark)
+ {
+ // 燃料不足,重置计时器但跳过这次标记
+ ticksUntilNextMarkDeconstruction = Mathf.RoundToInt(Props.markDeconstructionInterval / currentWorkSpeedMultiplier);
+ return;
+ }
+ }
+
+ StartMarking(target);
+ }
+
+ // 重置计时器,无论是否成功找到目标
+ ticksUntilNextMarkDeconstruction = Mathf.RoundToInt(Props.markDeconstructionInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ ticksUntilNextMarkDeconstruction--;
+ }
+ }
+ }
+
+ // 防止长时间不工作
+ public override void CompTickRare()
+ {
+ base.CompTickRare();
+
+ if (!isWorking && ticksUntilNextConversion > Props.conversionInterval * 10)
+ {
+ // 防止计时器溢出
+ ticksUntilNextConversion = Props.conversionInterval;
+ }
+
+ if (!isMarking && ticksUntilNextMarkDeconstruction > Props.markDeconstructionInterval * 10)
+ {
+ // 防止标记计时器溢出
+ ticksUntilNextMarkDeconstruction = Props.markDeconstructionInterval;
+ }
+ }
+
+ // 保存/加载
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+
+ // 尸体转换状态
+ Scribe_Values.Look(ref ticksUntilNextConversion, "ticksUntilNextConversion", Props.conversionInterval);
+ Scribe_Values.Look(ref isWorking, "isWorking", false);
+ Scribe_Values.Look(ref workTicksRemaining, "workTicksRemaining", 0);
+
+ // 标记拆除状态
+ Scribe_Values.Look(ref autoMarkForDeconstructionEnabled, "autoMarkForDeconstructionEnabled", true);
+ Scribe_Values.Look(ref ticksUntilNextMarkDeconstruction, "ticksUntilNextMarkDeconstruction", Props.markDeconstructionInterval);
+ Scribe_Values.Look(ref isMarking, "isMarking", false);
+ Scribe_Values.Look(ref markingTicksRemaining, "markingTicksRemaining", 0);
+
+ // 保存目标尸体的引用
+ if (Scribe.mode == LoadSaveMode.Saving)
+ {
+ bool hasTarget = targetCorpse != null && targetCorpse.Spawned;
+ Scribe_Values.Look(ref hasTarget, "hasTarget", false);
+ if (hasTarget)
+ {
+ Scribe_References.Look(ref targetCorpse, "targetCorpse");
+ }
+
+ bool hasMarkingTarget = markingTargetBuilding != null && markingTargetBuilding.Spawned;
+ Scribe_Values.Look(ref hasMarkingTarget, "hasMarkingTarget", false);
+ if (hasMarkingTarget)
+ {
+ Scribe_References.Look(ref markingTargetBuilding, "markingTargetBuilding");
+ }
+ }
+ else if (Scribe.mode == LoadSaveMode.LoadingVars)
+ {
+ bool hasTarget = false;
+ Scribe_Values.Look(ref hasTarget, "hasTarget", false);
+ if (hasTarget)
+ {
+ Scribe_References.Look(ref targetCorpse, "targetCorpse");
+ }
+
+ bool hasMarkingTarget = false;
+ Scribe_Values.Look(ref hasMarkingTarget, "hasMarkingTarget", false);
+ if (hasMarkingTarget)
+ {
+ Scribe_References.Look(ref markingTargetBuilding, "markingTargetBuilding");
+ }
+ }
+ }
+
+ // 检查字符串
+ public override string CompInspectStringExtra()
+ {
+ var builder = new StringBuilder();
+
+ if (Props.requiresPower)
+ {
+ builder.AppendLine("ARA_CorpseConverter.Power".Translate(HasPower ? "On".Translate() : "Off".Translate()));
+ }
+
+ if (Props.requiresFuel)
+ {
+ if (CompRefuelable != null)
+ {
+ builder.AppendLine("ARA_CorpseConverter.Fuel".Translate(
+ CompRefuelable.Fuel.ToString("F1"),
+ CompRefuelable.TargetFuelLevel.ToString("F1")));
+
+ if (Props.fuelConsumptionPerConversion > 0)
+ {
+ builder.AppendLine("ARA_CorpseConverter.FuelPerConversion".Translate(
+ Props.fuelConsumptionPerConversion.ToString("F1")));
+ }
+ }
+ else
+ {
+ builder.AppendLine("ARA_CorpseConverter.NoFuelComponent".Translate());
+ }
+ }
+
+ if (isWorking)
+ {
+ float progressPercent = 1f - ((float)workTicksRemaining / (Props.conversionInterval * 0.1f));
+ builder.AppendLine("ARA_CorpseConverter.WorkingProgress".Translate(
+ progressPercent.ToStringPercent()));
+ if (targetCorpse != null)
+ {
+ builder.AppendLine("ARA_CorpseConverter.TargetCorpse".Translate(
+ targetCorpse.InnerPawn?.LabelShort ?? "unknown"));
+ }
+ }
+ else
+ {
+ float daysUntilConversion = ticksUntilNextConversion / 60000f;
+ builder.AppendLine("ARA_CorpseConverter.NextConversion".Translate(
+ daysUntilConversion.ToString("F1")));
+ }
+
+ builder.AppendLine("ARA_CorpseConverter.ConversionRadius".Translate(
+ Props.conversionRadius.ToString("F1")));
+ return builder.ToString().TrimEndNewlines();
+ }
+
+ // 切换自动标记功能
+ private void ToggleAutoMarking()
+ {
+ autoMarkForDeconstructionEnabled = !autoMarkForDeconstructionEnabled;
+
+ if (autoMarkForDeconstructionEnabled)
+ {
+ Messages.Message("ARA_CorpseConverter.AutoMarkEnabled".Translate(),
+ parent, MessageTypeDefOf.PositiveEvent);
+ }
+ else
+ {
+ Messages.Message("ARA_CorpseConverter.AutoMarkDisabled".Translate(),
+ parent, MessageTypeDefOf.NeutralEvent);
+ }
+ }
+
+ // 获取Gizmos
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ foreach (var gizmo in base.CompGetGizmosExtra())
+ {
+ yield return gizmo;
+ }
+
+ // 自动标记拆除切换按钮
+ if (Props.enableAutoMarkForDeconstruction && parent.Faction == Faction.OfPlayer)
+ {
+ yield return new Command_Toggle
+ {
+ defaultLabel = "ARA_CorpseConverter.ToggleAutoMark".Translate(),
+ defaultDesc = "ARA_CorpseConverter.ToggleAutoMarkDesc".Translate(),
+ icon = ContentFinder.Get("UI/Designators/Deconstruct", false) ?? BaseContent.BadTex,
+ isActive = () => autoMarkForDeconstructionEnabled,
+ toggleAction = ToggleAutoMarking,
+ hotKey = KeyBindingDefOf.Misc4
+ };
+ }
+
+ // 开发模式下的调试命令
+ if (DebugSettings.ShowDevGizmos)
+ {
+ yield return new Command_Action
+ {
+ defaultLabel = "DEV: Test Conversion",
+ action = delegate
+ {
+ if (TryGetValidTargetCorpse(out Corpse corpse))
+ {
+ StartWorking(corpse);
+ }
+ else
+ {
+ Messages.Message("No valid corpses found", parent, MessageTypeDefOf.RejectInput);
+ }
+ }
+ };
+
+ yield return new Command_Action
+ {
+ defaultLabel = "DEV: Reset Timer",
+ action = delegate
+ {
+ ticksUntilNextConversion = 0;
+ }
+ };
+
+ yield return new Command_Action
+ {
+ defaultLabel = "DEV: Test Marking",
+ action = delegate
+ {
+ if (TryGetValidMarkingBuilding(out Thing building))
+ {
+ StartMarking(building);
+ }
+ else
+ {
+ Messages.Message("No valid buildings found", parent, MessageTypeDefOf.RejectInput);
+ }
+ }
+ };
+ }
+ }
+
+ // 绘制选择时的额外效果
+ public override void PostDrawExtraSelectionOverlays()
+ {
+ base.PostDrawExtraSelectionOverlays();
+
+ if (Props.showRadius)
+ {
+ // 显示转换半径
+ GenDraw.DrawRadiusRing(parent.Position, Props.conversionRadius, Color.red);
+
+ // 显示标记半径(如果不同)
+ if (Props.markDeconstructionRadius != Props.conversionRadius)
+ {
+ GenDraw.DrawRadiusRing(parent.Position, Props.markDeconstructionRadius, new Color(1f, 0.5f, 0f, 0.5f));
+ }
+ }
+ }
+
+ // 建筑被销毁时清理
+ public override void PostDestroy(DestroyMode mode, Map previousMap)
+ {
+ base.PostDestroy(mode, previousMap);
+ ResetWorkState();
+ ResetMarkingState();
+ }
+
+ // 建筑生成时初始化
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+ refuelableComponentCached = false; // 重置缓存,重新获取组件
+
+ // 初始化计时器
+ if (!respawningAfterLoad)
+ {
+ ticksUntilNextConversion = Props.conversionInterval;
+ autoMarkForDeconstructionEnabled = Props.enableAutoMarkForDeconstruction;
+ ticksUntilNextMarkDeconstruction = Props.markDeconstructionInterval;
+ }
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompProperties_CorpseConverter.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompProperties_CorpseConverter.cs
new file mode 100644
index 0000000..90aae18
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_CorpseConverter/CompProperties_CorpseConverter.cs
@@ -0,0 +1,125 @@
+// File: Comps/CompProperties_CorpseConverter.cs
+using RimWorld;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_CorpseConverter : CompProperties
+ {
+ // 转换目标物品定义(必须是建筑)
+ public ThingDef targetThingDef;
+
+ // 转换数量(每次转换生成多少个目标物品)
+ public int targetThingCount = 1;
+
+ // 基础转换间隔(游戏刻)
+ public int conversionInterval = 60000; // 默认1天
+
+ // 转换半径(以单元格为单位)
+ public float conversionRadius = 8f;
+
+ // 是否需要电源
+ public bool requiresPower = false;
+
+ // 电源开启时的工作速度乘数
+ public float poweredWorkSpeedMultiplier = 1.5f;
+
+ // 需要燃料
+ public bool requiresFuel = false;
+
+ // 每次转换消耗的燃料量
+ public float fuelConsumptionPerConversion = 5f;
+
+ // 最小燃料量要求(低于此值不工作)
+ public float minFuelToOperate = 0.1f;
+
+ // 接受哪些种类的尸体(可选,如果为空则接受所有尸体)
+ public List acceptedCorpseDefs;
+
+ // 是否显示视觉效果
+ public bool showVisualEffects = true;
+
+ // 工作时的效果器
+ public EffecterDef workingEffecter;
+
+ // 转换时的效果器
+ public EffecterDef conversionEffecter;
+
+ // 工作时的声音
+ public SoundDef workingSound;
+
+ // 转换时的声音
+ public SoundDef conversionSound;
+
+ // 转换完成时的声音
+ public SoundDef completionSound;
+
+ // 是否需要房间
+ public bool requiresRoom = false;
+
+ // 需要的最低房间评分(可选)
+ public float minRoomScore = -9999f;
+
+ // 是否显示转换进度
+ public bool showProgress = true;
+
+ // 是否显示转换半径
+ public bool showRadius = true;
+
+ // --- 新增:自动标记拆除功能 ---
+
+ // 是否启用自动标记拆除功能
+ public bool enableAutoMarkForDeconstruction = true;
+
+ // 自动标记拆除间隔(游戏刻)
+ public int markDeconstructionInterval = 120000; // 默认2天
+
+ // 标记拆除半径(可以不同于转换半径)
+ public float markDeconstructionRadius = 8f;
+
+ // 每次标记消耗的燃料量(可选)
+ public float fuelConsumptionPerMark = 2f;
+
+ // 标记效果器
+ public EffecterDef markEffecter;
+
+ // 标记时的声音
+ public SoundDef markSound;
+
+ // 标记完成时的声音
+ public SoundDef markCompleteSound;
+
+ // 是否排除机械族尸体
+ public bool excludeMechanoidCorpses = true;
+
+ public CompProperties_CorpseConverter()
+ {
+ compClass = typeof(CompCorpseConverter);
+ }
+
+ // 验证配置
+ public override void ResolveReferences(ThingDef parentDef)
+ {
+ base.ResolveReferences(parentDef);
+
+ if (targetThingDef == null)
+ {
+ Log.Warning($"CompProperties_CorpseConverter on {parentDef.defName} has no targetThingDef specified!");
+ }
+
+ // 检查目标物品是否是建筑
+ if (targetThingDef != null && targetThingDef.category != ThingCategory.Building)
+ {
+ Log.Warning($"CompProperties_CorpseConverter on {parentDef.defName}: targetThingDef {targetThingDef.defName} is not a building, but auto-deconstruction requires a building!");
+ }
+
+ // 如果未指定标记半径,使用转换半径
+ if (markDeconstructionRadius <= 0)
+ {
+ markDeconstructionRadius = conversionRadius;
+ }
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs
index 99fdb48..770cafd 100644
--- a/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_SwarmMaintenance/Comp_SwarmMaintenance.cs
@@ -323,8 +323,8 @@ namespace ArachnaeSwarm
// 只在玩家控制下显示
if (parent.Faction?.IsPlayer == true)
{
- // 调试按钮:手动触发寻找维护者
- if (Prefs.DevMode)
+ // 调试按钮:手动触发寻找维护者 - 仅在GodMode下显示
+ if (DebugSettings.godMode)
{
yield return new Command_Action
{
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompProperties_TerrainChanger.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompProperties_TerrainChanger.cs
new file mode 100644
index 0000000..f2839af
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompProperties_TerrainChanger.cs
@@ -0,0 +1,104 @@
+// File: Comps/CompProperties_TerrainChanger.cs
+using RimWorld;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_TerrainChanger : CompProperties
+ {
+ // 目标地形定义
+ public TerrainDef targetTerrain;
+
+ // 基础改变间隔(游戏刻)
+ public int baseChangeInterval = 60000; // 默认1天
+
+ // 改变半径(以单元格为单位)
+ public float changeRadius = 5f;
+
+ // 是否只在房间内改变
+ public bool onlyInSameRoom = true;
+
+ // 是否优先改变最近的地形
+ public bool prioritizeClosest = true;
+
+ // 需要的最低房间评分(可选)
+ public float minRoomScore = -9999f;
+
+ // 是否需要电源
+ public bool requiresPower = false;
+
+ // 电源开启时的工作速度乘数
+ public float poweredWorkSpeedMultiplier = 2f;
+
+ // 需要燃料
+ public bool requiresFuel = false;
+
+ // 每次地形改变消耗的燃料量
+ public float fuelConsumptionPerChange = 1f;
+
+ // 最小燃料量要求(低于此值不工作)
+ public float minFuelToOperate = 0.1f;
+
+ // 可接受的地形类型列表(可选,如果为空则接受所有可通行地形)
+ public List acceptedTerrains;
+
+ // 是否显示视觉效果
+ public bool showVisualEffects = true;
+
+ // 效果器定义
+ public EffecterDef workingEffecter;
+
+ // 工作时的声音
+ public SoundDef workingSound;
+
+ // 完成时的声音
+ public SoundDef completionSound;
+
+ // --- 新增:自动标记拆除功能 ---
+
+ // 是否启用自动标记拆除功能
+ public bool enableAutoMarkForRemoval = true;
+
+ // 自动标记拆除间隔(游戏刻)
+ public int markRemovalInterval = 120000; // 默认2天
+
+ // 标记拆除半径(可以不同于改变半径)
+ public float markRemovalRadius = 5f;
+
+ // 每次标记消耗的燃料量(可选)
+ public float fuelConsumptionPerMark = 0.5f;
+
+ // 标记效果器
+ public EffecterDef markEffecter;
+
+ // 标记时的声音
+ public SoundDef markSound;
+
+ // 标记完成时的声音
+ public SoundDef markCompleteSound;
+
+ public CompProperties_TerrainChanger()
+ {
+ compClass = typeof(CompTerrainChanger);
+ }
+
+ // 验证配置
+ public override void ResolveReferences(ThingDef parentDef)
+ {
+ base.ResolveReferences(parentDef);
+
+ if (targetTerrain == null)
+ {
+ Log.Warning($"CompProperties_TerrainChanger on {parentDef.defName} has no targetTerrain specified!");
+ }
+
+ // 如果未指定标记半径,使用改变半径
+ if (markRemovalRadius <= 0)
+ {
+ markRemovalRadius = changeRadius;
+ }
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompTerrainChanger.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompTerrainChanger.cs
new file mode 100644
index 0000000..70e040f
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Comps/ARA_TerrainChanger/CompTerrainChanger.cs
@@ -0,0 +1,825 @@
+// File: Comps/CompTerrainChanger.cs
+using RimWorld;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+using Verse.Sound;
+using System.Text;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class CompTerrainChanger : ThingComp
+ {
+ // 属性引用
+ private CompProperties_TerrainChanger Props => (CompProperties_TerrainChanger)props;
+
+ // 状态变量
+ private int ticksUntilNextChange;
+ private bool isWorking = false;
+ private int workTicksRemaining = 0;
+ private IntVec3 targetCell = IntVec3.Invalid;
+ private Effecter effecter;
+
+ // --- 新增:自动标记拆除状态 ---
+ private bool autoMarkForRemovalEnabled = true;
+ private int ticksUntilNextMarkRemoval;
+ private bool isMarking = false;
+ private int markingTicksRemaining = 0;
+ private IntVec3 markingTargetCell = IntVec3.Invalid;
+ private Effecter markingEffecter;
+
+ // 当前工作速度乘数
+ private float currentWorkSpeedMultiplier = 1.0f;
+
+ // 缓存燃料组件
+ private CompRefuelableNutrition_WithKey compRefuelable;
+ private bool refuelableComponentCached = false;
+
+ // 获取燃料组件
+ private CompRefuelableNutrition_WithKey CompRefuelable
+ {
+ get
+ {
+ if (!refuelableComponentCached)
+ {
+ compRefuelable = parent.TryGetComp();
+ refuelableComponentCached = true;
+ }
+ return compRefuelable;
+ }
+ }
+
+ // 检查燃料是否充足
+ private bool HasSufficientFuel
+ {
+ get
+ {
+ if (!Props.requiresFuel)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ return CompRefuelable.Fuel >= Props.minFuelToOperate;
+ }
+ }
+
+ // 检查是否有足够的燃料用于标记
+ private bool HasSufficientFuelForMarking
+ {
+ get
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ return CompRefuelable.Fuel >= Props.fuelConsumptionPerMark;
+ }
+ }
+
+ // 消耗燃料(用于地形改变)
+ private bool ConsumeFuelIfNeeded()
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerChange <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ if (CompRefuelable.Fuel >= Props.fuelConsumptionPerChange)
+ {
+ CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerChange);
+ return true;
+ }
+
+ return false;
+ }
+
+ // 消耗标记燃料
+ private bool ConsumeMarkingFuelIfNeeded()
+ {
+ if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
+ return true;
+
+ if (CompRefuelable == null)
+ return false;
+
+ if (CompRefuelable.Fuel >= Props.fuelConsumptionPerMark)
+ {
+ CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerMark);
+ return true;
+ }
+
+ return false;
+ }
+
+ // 获取电源状态
+ private bool HasPower
+ {
+ get
+ {
+ if (!Props.requiresPower)
+ return true;
+
+ var compPower = parent.TryGetComp();
+ return compPower != null && compPower.PowerOn;
+ }
+ }
+
+ // 获取房间
+ private Room GetRoom()
+ {
+ var map = parent.Map;
+ if (map == null)
+ return null;
+
+ return parent.Position.GetRoom(map);
+ }
+
+ // 检查是否满足基本操作条件
+ private bool CanOperate()
+ {
+ // 检查是否有电
+ if (Props.requiresPower && !HasPower)
+ return false;
+
+ // 检查是否有足够的燃料
+ if (Props.requiresFuel && !HasSufficientFuel)
+ return false;
+
+ // 检查是否在房间内(如果需要)
+ if (Props.onlyInSameRoom)
+ {
+ var room = GetRoom();
+ if (room == null || !room.ProperRoom)
+ return false;
+
+ // 检查房间评分
+ if (room.GetStat(RoomStatDefOf.Impressiveness) < Props.minRoomScore)
+ return false;
+ }
+
+ return true;
+ }
+
+ // 检查是否可以执行标记操作
+ private bool CanMarkForRemoval()
+ {
+ if (!Props.enableAutoMarkForRemoval || !autoMarkForRemovalEnabled)
+ return false;
+
+ if (!CanOperate())
+ return false;
+
+ // 检查标记燃料
+ if (Props.requiresFuel && !HasSufficientFuelForMarking)
+ return false;
+
+ return true;
+ }
+
+ // 获取有效的工作单元格(地形改变)
+ private bool TryGetValidTargetCell(out IntVec3 result)
+ {
+ result = IntVec3.Invalid;
+ var map = parent.Map;
+ if (map == null)
+ return false;
+
+ // 获取搜索范围
+ var center = parent.Position;
+ int radius = Mathf.CeilToInt(Props.changeRadius);
+
+ // 获取房间(如果需要)
+ Room parentRoom = null;
+ if (Props.onlyInSameRoom)
+ {
+ parentRoom = GetRoom();
+ if (parentRoom == null)
+ return false;
+ }
+
+ // 收集所有候选单元格
+ List candidateCells = new List();
+
+ for (int x = -radius; x <= radius; x++)
+ {
+ for (int z = -radius; z <= radius; z++)
+ {
+ IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
+
+ if (!cell.InBounds(map))
+ continue;
+
+ // 检查距离
+ float distance = cell.DistanceTo(center);
+ if (distance > Props.changeRadius)
+ continue;
+
+ // 检查房间(如果需要)
+ if (Props.onlyInSameRoom)
+ {
+ var cellRoom = cell.GetRoom(map);
+ if (cellRoom == null || cellRoom != parentRoom)
+ continue;
+ }
+
+ // 获取当前地形
+ TerrainDef currentTerrain = map.terrainGrid.TerrainAt(cell);
+
+ // 如果已经是目标地形,跳过
+ if (currentTerrain == Props.targetTerrain)
+ continue;
+
+ // 检查是否在可接受地形列表中(如果有定义)
+ if (Props.acceptedTerrains != null && Props.acceptedTerrains.Count > 0)
+ {
+ if (!Props.acceptedTerrains.Contains(currentTerrain))
+ continue;
+ }
+
+ candidateCells.Add(cell);
+ }
+ }
+
+ if (candidateCells.Count == 0)
+ return false;
+
+ // 根据设置选择单元格
+ if (Props.prioritizeClosest)
+ {
+ // 找到最近的单元格
+ float closestDistance = float.MaxValue;
+ IntVec3 closestCell = IntVec3.Invalid;
+
+ foreach (var cell in candidateCells)
+ {
+ float distance = cell.DistanceTo(center);
+ if (distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestCell = cell;
+ }
+ }
+
+ if (closestCell.IsValid)
+ {
+ result = closestCell;
+ return true;
+ }
+ }
+ else
+ {
+ // 随机选择一个单元格
+ result = candidateCells.RandomElement();
+ return true;
+ }
+
+ return false;
+ }
+
+ // 获取有效的标记拆除单元格
+ private bool TryGetValidMarkingCell(out IntVec3 result)
+ {
+ result = IntVec3.Invalid;
+ var map = parent.Map;
+ if (map == null)
+ return false;
+
+ // 获取搜索范围
+ var center = parent.Position;
+ int radius = Mathf.CeilToInt(Props.markRemovalRadius);
+
+ // 获取房间(如果需要)
+ Room parentRoom = null;
+ if (Props.onlyInSameRoom)
+ {
+ parentRoom = GetRoom();
+ if (parentRoom == null)
+ return false;
+ }
+
+ // 收集所有候选单元格
+ List candidateCells = new List();
+
+ for (int x = -radius; x <= radius; x++)
+ {
+ for (int z = -radius; z <= radius; z++)
+ {
+ IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
+
+ if (!cell.InBounds(map))
+ continue;
+
+ // 检查距离
+ float distance = cell.DistanceTo(center);
+ if (distance > Props.markRemovalRadius)
+ continue;
+
+ // 检查房间(如果需要)
+ if (Props.onlyInSameRoom)
+ {
+ var cellRoom = cell.GetRoom(map);
+ if (cellRoom == null || cellRoom != parentRoom)
+ continue;
+ }
+
+ // 获取当前地形
+ TerrainDef currentTerrain = map.terrainGrid.TerrainAt(cell);
+
+ // 如果不是目标地形,跳过(只标记可以生成的地形)
+ if (currentTerrain != Props.targetTerrain)
+ continue;
+
+ // 检查是否已经标记了拆除
+ if (map.designationManager.DesignationAt(cell, DesignationDefOf.RemoveFloor) != null)
+ continue;
+
+ // 检查是否可以移除
+ if (!map.terrainGrid.CanRemoveTopLayerAt(cell))
+ continue;
+
+ // 检查是否有建筑阻挡
+ if (WorkGiver_ConstructRemoveFloor.AnyBuildingBlockingFloorRemoval(cell, map))
+ continue;
+
+ candidateCells.Add(cell);
+ }
+ }
+
+ if (candidateCells.Count == 0)
+ return false;
+
+ // 根据设置选择单元格
+ if (Props.prioritizeClosest)
+ {
+ // 找到最近的单元格
+ float closestDistance = float.MaxValue;
+ IntVec3 closestCell = IntVec3.Invalid;
+
+ foreach (var cell in candidateCells)
+ {
+ float distance = cell.DistanceTo(center);
+ if (distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestCell = cell;
+ }
+ }
+
+ if (closestCell.IsValid)
+ {
+ result = closestCell;
+ return true;
+ }
+ }
+ else
+ {
+ // 随机选择一个单元格
+ result = candidateCells.RandomElement();
+ return true;
+ }
+
+ return false;
+ }
+
+ // 开始工作(地形改变)
+ private void StartWorking(IntVec3 targetCell)
+ {
+ this.targetCell = targetCell;
+ this.isWorking = true;
+
+ // 计算工作时间(基于距离)
+ float distance = targetCell.DistanceTo(parent.Position);
+ float workTimeFactor = 1f + (distance / Props.changeRadius) * 0.5f; // 距离越远,时间越长
+
+ int baseWorkTime = Mathf.RoundToInt(Props.baseChangeInterval * 0.1f); // 工作时间为间隔的10%
+ workTicksRemaining = Mathf.RoundToInt(baseWorkTime * workTimeFactor / currentWorkSpeedMultiplier);
+
+ // 播放声音
+ if (Props.workingSound != null)
+ {
+ Props.workingSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
+ }
+ }
+
+ // 开始标记工作
+ private void StartMarking(IntVec3 targetCell)
+ {
+ this.markingTargetCell = targetCell;
+ this.isMarking = true;
+
+ // 计算标记时间(基于距离)
+ float distance = targetCell.DistanceTo(parent.Position);
+ float workTimeFactor = 1f + (distance / Props.markRemovalRadius) * 0.5f;
+
+ int baseMarkTime = Mathf.RoundToInt(Props.markRemovalInterval * 0.05f); // 标记时间为间隔的5%
+ markingTicksRemaining = Mathf.RoundToInt(baseMarkTime * workTimeFactor / currentWorkSpeedMultiplier);
+
+ // 播放标记声音
+ if (Props.markSound != null)
+ {
+ Props.markSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
+ }
+ }
+
+ // 完成工作(地形改变)
+ private void CompleteWork()
+ {
+ var map = parent.Map;
+ if (map == null || !targetCell.IsValid || !targetCell.InBounds(map))
+ {
+ ResetWorkState();
+ return;
+ }
+
+ // 检查并消耗燃料
+ if (!ConsumeFuelIfNeeded())
+ {
+ Messages.Message("ARA_TerrainChanger.InsufficientFuel".Translate(),
+ new TargetInfo(targetCell, map), MessageTypeDefOf.NegativeEvent);
+ ResetWorkState();
+ return;
+ }
+
+ // 获取当前地形
+ TerrainDef currentTerrain = map.terrainGrid.TerrainAt(targetCell);
+
+ // 记录之前的地形
+ TerrainDef previousTerrain = currentTerrain;
+
+ // 改变地形
+ map.terrainGrid.SetTerrain(targetCell, Props.targetTerrain);
+
+ // 播放完成声音
+ if (Props.completionSound != null)
+ {
+ Props.completionSound.PlayOneShot(new TargetInfo(targetCell, map));
+ }
+
+ // 显示消息(可选)
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[TerrainChanger] Changed terrain at {targetCell} from {previousTerrain?.defName ?? "null"} to {Props.targetTerrain.defName}");
+ }
+
+ ResetWorkState();
+ }
+
+ // 完成标记工作
+ private void CompleteMarking()
+ {
+ var map = parent.Map;
+ if (map == null || !markingTargetCell.IsValid || !markingTargetCell.InBounds(map))
+ {
+ ResetMarkingState();
+ return;
+ }
+
+ // 检查并消耗标记燃料
+ if (!ConsumeMarkingFuelIfNeeded())
+ {
+ Messages.Message("ARA_TerrainChanger.InsufficientFuelForMarking".Translate(),
+ new TargetInfo(markingTargetCell, map), MessageTypeDefOf.NegativeEvent);
+ ResetMarkingState();
+ return;
+ }
+
+ // 获取当前地形
+ TerrainDef currentTerrain = map.terrainGrid.TerrainAt(markingTargetCell);
+
+ // 确保是目标地形(安全检查)
+ if (currentTerrain != Props.targetTerrain)
+ {
+ ResetMarkingState();
+ return;
+ }
+
+ // 添加拆除标记
+ map.designationManager.AddDesignation(new Designation(markingTargetCell, DesignationDefOf.RemoveFloor));
+
+ // 播放完成声音
+ if (Props.markCompleteSound != null)
+ {
+ Props.markCompleteSound.PlayOneShot(new TargetInfo(markingTargetCell, map));
+ }
+
+ // 显示消息(可选)
+ if (Prefs.DevMode)
+ {
+ Log.Message($"[TerrainChanger] Marked terrain at {markingTargetCell} ({currentTerrain.defName}) for removal");
+ }
+
+ ResetMarkingState();
+ }
+
+ // 重置工作状态
+ private void ResetWorkState()
+ {
+ isWorking = false;
+ workTicksRemaining = 0;
+ targetCell = IntVec3.Invalid;
+
+ // 清理效果器
+ if (effecter != null)
+ {
+ effecter.Cleanup();
+ effecter = null;
+ }
+ }
+
+ // 重置标记状态
+ private void ResetMarkingState()
+ {
+ isMarking = false;
+ markingTicksRemaining = 0;
+ markingTargetCell = IntVec3.Invalid;
+
+ // 清理标记效果器
+ if (markingEffecter != null)
+ {
+ markingEffecter.Cleanup();
+ markingEffecter = null;
+ }
+ }
+
+ // 更新工作速度
+ private void UpdateWorkSpeed()
+ {
+ float multiplier = 1.0f;
+
+ if (Props.requiresPower && HasPower)
+ {
+ multiplier *= Props.poweredWorkSpeedMultiplier;
+ }
+
+ if (Props.requiresFuel && HasSufficientFuel)
+ {
+ // 燃料充足时可能有额外的速度加成
+ // 可以在这里添加燃料相关的速度加成
+ }
+
+ currentWorkSpeedMultiplier = multiplier;
+ }
+
+ // Tick更新
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ // --- 处理地形改变 ---
+ if (isWorking)
+ {
+ workTicksRemaining--;
+
+ if (workTicksRemaining <= 0)
+ {
+ CompleteWork();
+ }
+ }
+ else if (CanOperate())
+ {
+ UpdateWorkSpeed();
+
+ // 等待下一次改变
+ if (ticksUntilNextChange <= 0)
+ {
+ // 尝试找到有效目标单元格
+ if (TryGetValidTargetCell(out IntVec3 target))
+ {
+ // 在开始工作前再次检查燃料
+ if (Props.requiresFuel && Props.fuelConsumptionPerChange > 0)
+ {
+ if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerChange)
+ {
+ // 燃料不足,重置计时器但跳过这次工作
+ ticksUntilNextChange = Mathf.RoundToInt(Props.baseChangeInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ StartWorking(target);
+ }
+ }
+ else
+ {
+ StartWorking(target);
+ }
+ }
+
+ // 重置计时器,无论是否成功找到目标
+ ticksUntilNextChange = Mathf.RoundToInt(Props.baseChangeInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ ticksUntilNextChange--;
+ }
+ }
+
+ // --- 处理自动标记拆除 ---
+ if (isMarking)
+ {
+ markingTicksRemaining--;
+
+ if (markingTicksRemaining <= 0)
+ {
+ CompleteMarking();
+ }
+ }
+ else if (CanMarkForRemoval())
+ {
+ // 等待下一次标记
+ if (ticksUntilNextMarkRemoval <= 0)
+ {
+ // 尝试找到有效标记单元格
+ if (TryGetValidMarkingCell(out IntVec3 target))
+ {
+ // 在开始标记前再次检查燃料
+ if (Props.requiresFuel && Props.fuelConsumptionPerMark > 0)
+ {
+ if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerMark)
+ {
+ // 燃料不足,重置计时器但跳过这次标记
+ ticksUntilNextMarkRemoval = Mathf.RoundToInt(Props.markRemovalInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ StartMarking(target);
+ }
+ }
+ else
+ {
+ StartMarking(target);
+ }
+ }
+
+ // 重置计时器,无论是否成功找到目标
+ ticksUntilNextMarkRemoval = Mathf.RoundToInt(Props.markRemovalInterval / currentWorkSpeedMultiplier);
+ }
+ else
+ {
+ ticksUntilNextMarkRemoval--;
+ }
+ }
+ }
+
+ // 防止长时间不工作
+ public override void CompTickRare()
+ {
+ base.CompTickRare();
+
+ if (!isWorking && ticksUntilNextChange > Props.baseChangeInterval * 10)
+ {
+ // 防止计时器溢出
+ ticksUntilNextChange = Props.baseChangeInterval;
+ }
+
+ if (!isMarking && ticksUntilNextMarkRemoval > Props.markRemovalInterval * 10)
+ {
+ // 防止标记计时器溢出
+ ticksUntilNextMarkRemoval = Props.markRemovalInterval;
+ }
+ }
+
+ // 保存/加载
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+
+ // 地形改变状态
+ Scribe_Values.Look(ref ticksUntilNextChange, "ticksUntilNextChange", Props.baseChangeInterval);
+ Scribe_Values.Look(ref isWorking, "isWorking", false);
+ Scribe_Values.Look(ref workTicksRemaining, "workTicksRemaining", 0);
+ Scribe_Values.Look(ref targetCell, "targetCell", IntVec3.Invalid);
+
+ // 标记拆除状态
+ Scribe_Values.Look(ref autoMarkForRemovalEnabled, "autoMarkForRemovalEnabled", true);
+ Scribe_Values.Look(ref ticksUntilNextMarkRemoval, "ticksUntilNextMarkRemoval", Props.markRemovalInterval);
+ Scribe_Values.Look(ref isMarking, "isMarking", false);
+ Scribe_Values.Look(ref markingTicksRemaining, "markingTicksRemaining", 0);
+ Scribe_Values.Look(ref markingTargetCell, "markingTargetCell", IntVec3.Invalid);
+ }
+
+ // 检查字符串
+ public override string CompInspectStringExtra()
+ {
+ var builder = new StringBuilder();
+
+ if (Props.requiresPower)
+ {
+ builder.AppendLine("ARA_TerrainChanger.Power".Translate(HasPower ? "On".Translate() : "Off".Translate()));
+ }
+
+ if (Props.requiresFuel)
+ {
+ if (CompRefuelable != null)
+ {
+ builder.AppendLine("ARA_TerrainChanger.Fuel".Translate(
+ CompRefuelable.Fuel.ToString("F1"),
+ CompRefuelable.TargetFuelLevel.ToString("F1")));
+
+ if (Props.fuelConsumptionPerChange > 0)
+ {
+ builder.AppendLine("ARA_TerrainChanger.FuelPerChange".Translate(
+ Props.fuelConsumptionPerChange.ToString("F1")));
+ }
+
+ if (Props.fuelConsumptionPerMark > 0)
+ {
+ builder.AppendLine("ARA_TerrainChanger.FuelPerMark".Translate(
+ Props.fuelConsumptionPerMark.ToString("F1")));
+ }
+ }
+ else
+ {
+ builder.AppendLine("ARA_TerrainChanger.NoFuelComponent".Translate());
+ }
+ }
+
+ if (isWorking)
+ {
+ float progressPercent = 1f - ((float)workTicksRemaining / (Props.baseChangeInterval * 0.1f));
+ builder.AppendLine("ARA_TerrainChanger.WorkingProgress".Translate(
+ progressPercent.ToStringPercent()));
+ builder.AppendLine("ARA_TerrainChanger.TargetCell".Translate(targetCell));
+ }
+ else
+ {
+ float daysUntilChange = ticksUntilNextChange / 60000f;
+ builder.AppendLine("ARA_TerrainChanger.NextChange".Translate(
+ daysUntilChange.ToString("F1")));
+ }
+
+ builder.AppendLine("ARA_TerrainChanger.TargetTerrain".Translate(
+ Props.targetTerrain.LabelCap));
+ builder.AppendLine("ARA_TerrainChanger.ChangeRadius".Translate(
+ Props.changeRadius.ToString("F1")));
+
+ return builder.ToString().TrimEndNewlines();
+ }
+
+ // 切换自动标记功能
+ private void ToggleAutoMarking()
+ {
+ autoMarkForRemovalEnabled = !autoMarkForRemovalEnabled;
+
+ if (autoMarkForRemovalEnabled)
+ {
+ Messages.Message("ARA_TerrainChanger.AutoMarkEnabled".Translate(),
+ parent, MessageTypeDefOf.PositiveEvent);
+ }
+ else
+ {
+ Messages.Message("ARA_TerrainChanger.AutoMarkDisabled".Translate(),
+ parent, MessageTypeDefOf.NeutralEvent);
+ }
+ }
+
+ // 获取Gizmos
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ foreach (var gizmo in base.CompGetGizmosExtra())
+ {
+ yield return gizmo;
+ }
+
+ // 只有在启用了自动标记功能时才显示切换按钮
+ if (Props.enableAutoMarkForRemoval && parent.Faction == Faction.OfPlayer)
+ {
+ yield return new Command_Toggle
+ {
+ defaultLabel = "ARA_TerrainChanger.ToggleAutoMark".Translate(),
+ defaultDesc = "ARA_TerrainChanger.ToggleAutoMarkDesc".Translate(),
+ icon = ContentFinder.Get("UI/Designators/RemoveFloor", false) ?? BaseContent.BadTex,
+ isActive = () => autoMarkForRemovalEnabled,
+ toggleAction = ToggleAutoMarking,
+ hotKey = KeyBindingDefOf.Misc4
+ };
+ }
+ }
+
+ // 建筑被销毁时清理
+ public override void PostDestroy(DestroyMode mode, Map previousMap)
+ {
+ base.PostDestroy(mode, previousMap);
+ ResetWorkState();
+ ResetMarkingState();
+ }
+
+ // 建筑生成时初始化
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+ refuelableComponentCached = false; // 重置缓存,重新获取组件
+
+ // 初始化自动标记状态
+ if (!respawningAfterLoad)
+ {
+ autoMarkForRemovalEnabled = Props.enableAutoMarkForRemoval;
+ ticksUntilNextMarkRemoval = Props.markRemovalInterval;
+ }
+ }
+ }
+}
diff --git a/Source/ArachnaeSwarm/Hediffs/ARA_HediffComp_TopTurret/HediffComp_TopTurret.cs b/Source/ArachnaeSwarm/Hediffs/ARA_HediffComp_TopTurret/HediffComp_TopTurret.cs
index 83c2ef0..c486341 100644
--- a/Source/ArachnaeSwarm/Hediffs/ARA_HediffComp_TopTurret/HediffComp_TopTurret.cs
+++ b/Source/ArachnaeSwarm/Hediffs/ARA_HediffComp_TopTurret/HediffComp_TopTurret.cs
@@ -15,29 +15,14 @@ namespace ArachnaeSwarm
}
public ThingDef turretDef;
-
public float angleOffset;
-
public bool autoAttack = true;
+ public bool defaultEnabled = true;
}
[StaticConstructorOnStartup]
public class HediffComp_TopTurret : HediffComp, IAttackTargetSearcher
{
- // 添加 null 检查的属性
- private HediffCompProperties_TopTurret Props
- {
- get
- {
- if (this.props == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: props is null");
- return null;
- }
- return this.props as HediffCompProperties_TopTurret;
- }
- }
-
public Thing Thing
{
get
@@ -46,6 +31,14 @@ namespace ArachnaeSwarm
}
}
+ private HediffCompProperties_TopTurret Props
+ {
+ get
+ {
+ return (HediffCompProperties_TopTurret)this.props;
+ }
+ }
+
public Verb CurrentEffectiveVerb
{
get
@@ -74,11 +67,6 @@ namespace ArachnaeSwarm
{
get
{
- if (this.gun == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: gun is null");
- return null;
- }
return this.gun.TryGetComp();
}
}
@@ -87,13 +75,7 @@ namespace ArachnaeSwarm
{
get
{
- var comp = this.GunCompEq;
- if (comp == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: GunCompEq is null");
- return null;
- }
- return comp.PrimaryVerb;
+ return this.GunCompEq.PrimaryVerb;
}
}
@@ -105,10 +87,131 @@ namespace ArachnaeSwarm
}
}
+ public override void CompPostTick(ref float severityAdjustment)
+ {
+ base.CompPostTick(ref severityAdjustment);
+
+ if (!TurretEnabled)
+ {
+ ResetCurrentTarget();
+ return;
+ }
+
+ if (!this.CanShoot)
+ {
+ return;
+ }
+
+ if (this.currentTarget.IsValid)
+ {
+ this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
+ }
+
+ this.AttackVerb.VerbTick();
+
+ if (this.AttackVerb.state != VerbState.Bursting)
+ {
+ if (this.WarmingUp)
+ {
+ this.burstWarmupTicksLeft--;
+ if (this.burstWarmupTicksLeft == 0)
+ {
+ bool attackSuccess = this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
+ if (attackSuccess)
+ {
+ this.lastAttackTargetTick = Find.TickManager.TicksGame;
+ this.lastAttackedTarget = this.currentTarget;
+ }
+ return;
+ }
+ }
+ else
+ {
+ if (this.burstCooldownTicksLeft > 0)
+ {
+ this.burstCooldownTicksLeft--;
+ }
+
+ if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
+ {
+ // 自动寻找目标
+ this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
+
+ if (this.currentTarget.IsValid)
+ {
+ this.burstWarmupTicksLeft = 1;
+ return;
+ }
+
+ this.ResetCurrentTarget();
+ }
+ }
+ }
+ }
+
+ // 简化的Gizmos - 只有开关按钮
+ public override IEnumerable CompGetGizmos()
+ {
+ // 只有 pawn 被选中且是玩家派系时才显示按钮
+ if (this.Pawn.Faction == Faction.OfPlayer && Find.Selector.IsSelected(this.Pawn))
+ {
+ yield return new Command_Toggle
+ {
+ defaultLabel = "CommandToggleTurret".Translate(),
+ defaultDesc = "CommandToggleTurretDesc".Translate(),
+ icon = ContentFinder.Get("UI/Gizmos/ToggleTurret"),
+ isActive = () => TurretEnabled,
+ toggleAction = () => TurretEnabled = !TurretEnabled,
+ hotKey = KeyBindingDefOf.Misc1
+ };
+ }
+ }
+
+ // 简化的提示信息
+ public override string CompTipStringExtra
+ {
+ get
+ {
+ string baseString = base.CompTipStringExtra;
+ string turretStatus = TurretEnabled ? "Turret: Active" : "Turret: Inactive";
+ string targetStatus = "Target: ";
+
+ if (this.currentTarget.IsValid)
+ {
+ targetStatus += $"{this.currentTarget.Thing?.LabelCap ?? this.currentTarget.Cell.ToString()}";
+ }
+ else
+ {
+ targetStatus += "None";
+ }
+
+ string result = turretStatus + "\n" + targetStatus;
+ return string.IsNullOrEmpty(baseString) ? result : baseString + "\n" + result;
+ }
+ }
+
+ // 炮塔启用状态
+ public bool TurretEnabled
+ {
+ get { return turretEnabled; }
+ set
+ {
+ turretEnabled = value;
+ if (!turretEnabled)
+ {
+ ResetCurrentTarget(); // 禁用时重置目标
+ }
+ }
+ }
+
private bool CanShoot
{
get
{
+ // 检查炮塔是否启用
+ if (!TurretEnabled)
+ return false;
+
Pawn pawn;
if ((pawn = (this.Pawn)) != null)
{
@@ -147,7 +250,7 @@ namespace ArachnaeSwarm
{
get
{
- if (this.turretMat == null && this.Props?.turretDef?.graphicData != null)
+ if (this.turretMat == null)
{
this.turretMat = MaterialPool.MatFrom(this.Props.turretDef.graphicData.texPath);
}
@@ -159,71 +262,27 @@ namespace ArachnaeSwarm
{
get
{
- return this.Props?.autoAttack ?? false;
+ return this.Props.autoAttack;
}
}
public override void CompPostMake()
{
base.CompPostMake();
-
- // 添加 null 检查
- if (this.Props == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: Props is null in CompPostMake");
- return;
- }
-
this.MakeGun();
+ // 设置默认启用状态
+ TurretEnabled = Props.defaultEnabled;
}
private void MakeGun()
{
- // 添加详细的 null 检查
- if (this.Props == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: Props is null in MakeGun");
- return;
- }
-
- if (this.Props.turretDef == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: Props.turretDef is null");
- return;
- }
-
- try
- {
- this.gun = ThingMaker.MakeThing(this.Props.turretDef, null);
- if (this.gun == null)
- {
- ArachnaeLog.Debug($"HediffComp_TopTurret: Failed to create gun from turretDef '{this.Props.turretDef.defName}'");
- return;
- }
- this.UpdateGunVerbs();
- }
- catch (Exception ex)
- {
- ArachnaeLog.Debug($"HediffComp_TopTurret: Exception in MakeGun: {ex}");
- }
+ this.gun = ThingMaker.MakeThing(this.Props.turretDef, null);
+ this.UpdateGunVerbs();
}
private void UpdateGunVerbs()
{
- if (this.gun == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: gun is null in UpdateGunVerbs");
- return;
- }
-
- var comp = this.gun.TryGetComp();
- if (comp == null)
- {
- ArachnaeLog.Debug("HediffComp_TopTurret: CompEquippable is null");
- return;
- }
-
- List allVerbs = comp.AllVerbs;
+ List allVerbs = this.gun.TryGetComp().AllVerbs;
for (int i = 0; i < allVerbs.Count; i++)
{
Verb verb = allVerbs[i];
@@ -235,58 +294,6 @@ namespace ArachnaeSwarm
}
}
- public override void CompPostTick(ref float severityAdjustment)
- {
- base.CompPostTick(ref severityAdjustment);
-
- // 添加 null 检查
- if (this.AttackVerb == null)
- {
- return;
- }
-
- if (!this.CanShoot)
- {
- return;
- }
- if (this.currentTarget.IsValid)
- {
- this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
- }
- this.AttackVerb.VerbTick();
- if (this.AttackVerb.state != VerbState.Bursting)
- {
- if (this.WarmingUp)
- {
- this.burstWarmupTicksLeft--;
- if (this.burstWarmupTicksLeft == 0)
- {
- this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
- this.lastAttackTargetTick = Find.TickManager.TicksGame;
- this.lastAttackedTarget = this.currentTarget;
- return;
- }
- }
- else
- {
- if (this.burstCooldownTicksLeft > 0)
- {
- this.burstCooldownTicksLeft--;
- }
- if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
- {
- this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
- if (this.currentTarget.IsValid)
- {
- this.burstWarmupTicksLeft = 1;
- return;
- }
- this.ResetCurrentTarget();
- }
- }
- }
- }
-
private void ResetCurrentTarget()
{
this.currentTarget = LocalTargetInfo.Invalid;
@@ -301,11 +308,13 @@ namespace ArachnaeSwarm
Scribe_TargetInfo.Look(ref this.currentTarget, "currentTarget");
Scribe_Deep.Look(ref this.gun, "gun", Array.Empty());
Scribe_Values.Look(ref this.fireAtWill, "fireAtWill", true, false);
+ // 保存启用状态
+ Scribe_Values.Look(ref this.turretEnabled, "turretEnabled", Props.defaultEnabled, false);
+
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
if (this.gun == null)
{
- ArachnaeLog.Debug("CompTurrentGun had null gun after loading. Recreating.");
this.MakeGun();
return;
}
@@ -315,24 +324,18 @@ namespace ArachnaeSwarm
private const int StartShootIntervalTicks = 10;
- private static readonly CachedTexture ToggleTurretIcon = new CachedTexture("UI/Gizmos/ToggleTurret");
-
public Thing gun;
-
protected int burstCooldownTicksLeft;
-
protected int burstWarmupTicksLeft;
-
protected LocalTargetInfo currentTarget = LocalTargetInfo.Invalid;
-
private bool fireAtWill = true;
-
private LocalTargetInfo lastAttackedTarget = LocalTargetInfo.Invalid;
-
private int lastAttackTargetTick;
-
private float curRotation;
+ // 炮塔启用状态字段
+ private bool turretEnabled = true;
+
[Unsaved(false)]
public Material turretMat;
}
diff --git a/Source/ArachnaeSwarm/Jobs/JobDriver_StripChitin/JobDriver_StripChitin.cs b/Source/ArachnaeSwarm/Jobs/JobDriver_StripChitin/JobDriver_StripChitin.cs
index 1811cec..71c0129 100644
--- a/Source/ArachnaeSwarm/Jobs/JobDriver_StripChitin/JobDriver_StripChitin.cs
+++ b/Source/ArachnaeSwarm/Jobs/JobDriver_StripChitin/JobDriver_StripChitin.cs
@@ -112,7 +112,9 @@ namespace ArachnaeSwarm
int stripCount = (int)ChitinNeed.CurLevel;
if (stripCount < StripComp.Props.minStripAmount)
stripCount = StripComp.Props.minStripAmount;
-
+
+ stripCount = stripCount * 2;
+
// 获取甲壳物品定义
ThingDef carapaceDef = StripComp.CarapaceThingDef;
if (carapaceDef == null)
diff --git a/Source/ArachnaeSwarm/Buildings/Building_Ootheca/RoomRoleWorker_Incubator.cs b/Source/ArachnaeSwarm/RoomRole/RoomRoleWorker_Incubator.cs
similarity index 100%
rename from Source/ArachnaeSwarm/Buildings/Building_Ootheca/RoomRoleWorker_Incubator.cs
rename to Source/ArachnaeSwarm/RoomRole/RoomRoleWorker_Incubator.cs
diff --git a/Source/ArachnaeSwarm/Verbs/Verb_ShootSelfUnderfoot.cs b/Source/ArachnaeSwarm/Verbs/Verb_ShootSelfUnderfoot.cs
new file mode 100644
index 0000000..4973d07
--- /dev/null
+++ b/Source/ArachnaeSwarm/Verbs/Verb_ShootSelfUnderfoot.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+
+namespace ArachnaeSwarm
+{
+ public class Verb_ShootSelfUnderfoot : Verb_LaunchProjectile
+ {
+ // 重写ShotsPerBurst,与Verb_Shoot相同
+ protected override int ShotsPerBurst => base.BurstShotCount;
+
+ // 重写WarmupComplete,添加射击技能学习
+ public override void WarmupComplete()
+ {
+ base.WarmupComplete();
+
+ // 只有在目标是Pawn时才学习射击技能
+ if (currentTarget.Thing is Pawn targetPawn &&
+ !targetPawn.Downed &&
+ !targetPawn.IsColonyMech &&
+ CasterIsPawn &&
+ CasterPawn.skills != null)
+ {
+ float xp = targetPawn.HostileTo(caster) ? 170f : 20f;
+ float num2 = verbProps.AdjustedFullCycleTime(this, CasterPawn);
+ CasterPawn.skills.Learn(SkillDefOf.Shooting, xp * num2);
+ }
+ }
+
+ // 核心重写:将目标改为脚下
+ protected override bool TryCastShot()
+ {
+ // 保存原始目标
+ LocalTargetInfo originalTarget = currentTarget;
+
+ try
+ {
+ // 将目标改为施法者自己的位置
+ currentTarget = new LocalTargetInfo(caster.Position);
+
+ // 调用基类方法,但使用修改后的目标(脚下)
+ bool result = base.TryCastShot();
+
+ // 如果成功发射,记录射击次数
+ if (result && CasterIsPawn)
+ {
+ CasterPawn.records.Increment(RecordDefOf.ShotsFired);
+ }
+
+ return result;
+ }
+ finally
+ {
+ // 恢复原始目标(对于连续射击可能重要)
+ currentTarget = originalTarget;
+ }
+ }
+
+ // 重写CanHitTarget,因为目标是脚下,总是可以命中
+ public override bool CanHitTarget(LocalTargetInfo targ)
+ {
+ // 对于向脚下射击,我们总是允许(只要施法者存在)
+ if (caster == null || !caster.Spawned)
+ return false;
+
+ // 如果目标就是施法者自己,允许
+ if (targ == caster)
+ return true;
+
+ // 对于其他目标,使用默认逻辑
+ return base.CanHitTarget(targ);
+ }
+
+ // 重写CanHitTargetFrom,对于脚下射击总是返回true
+ public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ)
+ {
+ // 如果目标是施法者自己(或脚下),总是可以命中
+ if (targ.Thing == caster || (targ.IsValid && targ.Cell == caster.Position))
+ return true;
+
+ return base.CanHitTargetFrom(root, targ);
+ }
+
+ // 重写TryFindShootLineFromTo,对于脚下射击简化逻辑
+ public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine, bool ignoreRange = false)
+ {
+ // 如果目标是脚下,直接返回射击线
+ if (targ.IsValid && targ.Cell == caster.Position)
+ {
+ resultingLine = new ShootLine(root, targ.Cell);
+ return true;
+ }
+
+ // 否则使用基类逻辑
+ return base.TryFindShootLineFromTo(root, targ, out resultingLine, ignoreRange);
+ }
+
+ // 重写DrawHighlight,简化高亮显示
+ public override void DrawHighlight(LocalTargetInfo target)
+ {
+ // 绘制标准射程环
+ verbProps.DrawRadiusRing(caster.Position, this);
+
+ // 如果目标是有效的,绘制目标高亮
+ if (target.IsValid)
+ {
+ GenDraw.DrawTargetHighlight(target);
+
+ // 绘制目标周围的场半径
+ DrawHighlightFieldRadiusAroundTarget(target);
+ }
+ }
+
+ // 辅助方法:绘制彩色目标高亮
+ private void GenDraw_DrawTargetHighlightWithColor(LocalTargetInfo target, Color color)
+ {
+ GenDraw.DrawTargetHighlight(target);
+ }
+
+ // 重写OnGUI,显示自定义鼠标图标
+ public override void OnGUI(LocalTargetInfo target)
+ {
+ // 使用自定义图标或默认攻击图标
+ Texture2D icon;
+ if (!target.IsValid)
+ {
+ icon = TexCommand.CannotShoot;
+ }
+ else if (target.Cell == caster.Position)
+ {
+ // 可以使用自定义图标,这里使用攻击图标
+ icon = TexCommand.Attack;
+ }
+ else
+ {
+ icon = (UIIcon != BaseContent.BadTex) ? UIIcon : TexCommand.Attack;
+ }
+
+ GenUI.DrawMouseAttachment(icon);
+ }
+
+ // 重写ValidateTarget,允许向自己脚下射击
+ public override bool ValidateTarget(LocalTargetInfo target, bool showMessages = true)
+ {
+ // 如果目标是脚下,总是允许
+ if (target.IsValid && target.Cell == caster.Position)
+ return true;
+
+ // 否则使用基类验证逻辑
+ return base.ValidateTarget(target, showMessages);
+ }
+
+ // 重写Available,确保有抛射体,并允许在近战状态下使用
+ public override bool Available()
+ {
+ // 首先调用基类检查
+ if (!base.Available())
+ return false;
+
+ // 检查是否有抛射体
+ if (Projectile == null)
+ return false;
+
+ // 特殊处理:允许在近战威胁下使用
+ if (CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
+ {
+ return true;
+ }
+
+ return true;
+ }
+
+ // 重写OrderForceTarget,允许在近战距离内强制使用
+ public override void OrderForceTarget(LocalTargetInfo target)
+ {
+ // 如果是近战攻击,使用近战逻辑
+ if (verbProps.IsMeleeAttack)
+ {
+ Job job = JobMaker.MakeJob(JobDefOf.AttackMelee, target);
+ job.playerForced = true;
+ if (target.Thing is Pawn pawn)
+ {
+ job.killIncappedTarget = pawn.Downed;
+ }
+ CasterPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+ return;
+ }
+
+ // 检查是否在近战范围内,但允许向脚下射击
+ float minRange = verbProps.EffectiveMinRange(target, CasterPawn);
+ if (CasterIsPawn &&
+ (float)CasterPawn.Position.DistanceToSquared(target.Cell) < minRange * minRange &&
+ CasterPawn.Position.AdjacentTo8WayOrInside(target.Cell))
+ {
+ // 如果是向脚下射击,允许
+ if (target.IsValid && target.Cell == CasterPawn.Position)
+ {
+ // 允许向脚下射击
+ }
+ else
+ {
+ Messages.Message("MessageCantShootInMelee".Translate(), CasterPawn, MessageTypeDefOf.RejectInput, historical: false);
+ return;
+ }
+ }
+
+ // 创建射击工作
+ Job job2 = JobMaker.MakeJob(verbProps.ai_IsWeapon ? JobDefOf.AttackStatic : JobDefOf.UseVerbOnThing);
+ job2.verbToUse = this;
+ job2.targetA = target;
+ job2.endIfCantShootInMelee = false; // 设置为false,允许在近战中射击
+ CasterPawn.jobs.TryTakeOrderedJob(job2, JobTag.Misc);
+ }
+
+ // 重写TryStartCastOn,允许在近战状态下开始射击
+ public override bool TryStartCastOn(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, bool canHitNonTargetPawns = true, bool preventFriendlyFire = false, bool nonInterruptingSelfCast = false)
+ {
+ // 调用基类方法,但设置一个标志表示这是向脚下射击
+ bool isShootingUnderfoot = castTarg.IsValid && castTarg.Cell == caster.Position;
+
+ // 如果是向脚下射击,临时修改一些属性以允许近战射击
+ if (isShootingUnderfoot && CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
+ {
+ // 临时忽略近战威胁检查
+ bool originalAIProjectileLaunchingIgnoresMeleeThreats = verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats;
+ verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = true;
+
+ try
+ {
+ return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
+ }
+ finally
+ {
+ // 恢复原始值
+ verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = originalAIProjectileLaunchingIgnoresMeleeThreats;
+ }
+ }
+
+ return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
+ }
+
+ // 添加一个方法,检查是否在近战状态下
+ public bool IsInMeleeCombat()
+ {
+ if (!CasterIsPawn)
+ return false;
+
+ return CasterPawn.mindState?.MeleeThreatStillThreat == true;
+ }
+
+ // 重写BurstingTick,在近战状态下也继续射击
+ public override void BurstingTick()
+ {
+ base.BurstingTick();
+
+ // 在近战状态下也继续射击逻辑
+ if (IsInMeleeCombat() && state == VerbState.Bursting)
+ {
+ // 可以在这里添加近战状态下的特殊效果
+ }
+ }
+
+ // 添加自定义属性,用于控制是否总是向脚下发射
+ private bool alwaysShootUnderfoot = true;
+
+ public bool AlwaysShootUnderfoot
+ {
+ get => alwaysShootUnderfoot;
+ set => alwaysShootUnderfoot = value;
+ }
+
+ // 添加一个方法,允许临时关闭向脚下射击
+ public void SetShootUnderfoot(bool shootUnderfoot)
+ {
+ alwaysShootUnderfoot = shootUnderfoot;
+ }
+ }
+}
diff --git a/非公开资源/Content/Textures/Item/ARA_Carapace.sai2 b/非公开资源/Content/Textures/Item/ARA_Carapace.sai2
index b944f12..282f7ca 100644
Binary files a/非公开资源/Content/Textures/Item/ARA_Carapace.sai2 and b/非公开资源/Content/Textures/Item/ARA_Carapace.sai2 differ
diff --git a/非公开资源/Content/Textures/Terrain/Surfaces/ARA_InsectJelly_Terrain.png b/非公开资源/Content/Textures/Terrain/Surfaces/ARA_InsectJelly_Terrain.png
new file mode 100644
index 0000000..51ee441
Binary files /dev/null and b/非公开资源/Content/Textures/Terrain/Surfaces/ARA_InsectJelly_Terrain.png differ
diff --git a/非公开资源/Content/Textures/UI/Abilities/ARA_EggSpew.sai2 b/非公开资源/Content/Textures/UI/Abilities/ARA_EggSpew.sai2
index 91359d7..f323feb 100644
Binary files a/非公开资源/Content/Textures/UI/Abilities/ARA_EggSpew.sai2 and b/非公开资源/Content/Textures/UI/Abilities/ARA_EggSpew.sai2 differ
diff --git a/非公开资源/Content/Textures/UI/Commands/ARA_NodeSwarmIcon.sai2 b/非公开资源/Content/Textures/UI/Commands/ARA_NodeSwarmIcon.sai2
new file mode 100644
index 0000000..414dd53
Binary files /dev/null and b/非公开资源/Content/Textures/UI/Commands/ARA_NodeSwarmIcon.sai2 differ
diff --git a/非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2 b/非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2
index 9ff5052..f87e5c4 100644
Binary files a/非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2 and b/非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2 differ