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