This commit is contained in:
Tourswen
2026-01-28 13:48:48 +08:00
17 changed files with 1681 additions and 691 deletions

Binary file not shown.

View File

@@ -469,7 +469,7 @@
<hediffToApplyOnSuccess>ARA_HiveMindDrone</hediffToApplyOnSuccess>
<!-- Optional: A list of race ThingDefs that cannot be possessed -->
<raceBlacklist>
<li>ArachnaeQueen_Race</li>
<li>ArachnaeQueen_Race_Titan</li>
</raceBlacklist>
</li>
</comps>

View File

@@ -45,7 +45,7 @@
<PawnKindDef Name="ArachnaeQueen_Colonist" ParentName="ArachnaeQueenBasePawnKind">
<defName>ARA_ArachnaeQueen</defName>
<label>阿拉克涅女皇种</label>
<race>ArachnaeQueen_Race</race>
<race>ArachnaeQueen_Race_Titan</race>
<defaultFactionType>PlayerColony</defaultFactionType>
<invNutrition>0</invNutrition>
<backstoryFiltersOverride>
@@ -65,7 +65,7 @@
</abilities>
</PawnKindDef>
<AlienRace.RaceSettings>
<defName>ArachnaeQueen_RaceSettings</defName>
<defName>ArachnaeQueen_Race_TitanSettings</defName>
<pawnKindSettings>
<startingColonists>
<li>

View File

@@ -50,6 +50,7 @@
<race>
<body>BeetleLikeWithClaw</body>
<thinkTreeMain>ARA_Insect_WithPlanting</thinkTreeMain>
<thinkTreeConstant>ARA_Insect_Thinktree_Constant</thinkTreeConstant>
<foodType>CarnivoreAnimal,OvivoreAnimal</foodType>
<baseHungerRate>0.1</baseHungerRate>
<baseBodySize>0.5</baseBodySize>

View File

@@ -178,10 +178,637 @@
</li>
</comps>
</ThingDef>
<AlienRace.ThingDef_AlienRace Name="ARA_QueenBase" ParentName="ARA_PawnBase">
<defName>ArachnaeQueen_Race</defName>
<AlienRace.ThingDef_AlienRace Abstract="True" Name="ARA_QueenBase" ParentName="ARA_PawnBase">
<alienRace>
<!-- 核心设置 -->
<generalSettings>
<!-- 男性生成几率 -->
<maleGenderProbability>0</maleGenderProbability>
<!-- 无视年龄疾病 -->
<immuneToAge>true</immuneToAge>
<!-- 在口角中造成的最大伤害 -->
<maxDamageForSocialfight>15</maxDamageForSocialfight>
<!-- 免疫人类的异形歧视 -->
<immuneToXenophobia>false</immuneToXenophobia>
<!-- 最小的可生成成人背景的年龄 -->
<minAgeForAdulthood>0</minAgeForAdulthood>
<!-- 手术继承自人类 -->
<humanRecipeImport>false</humanRecipeImport>
<!-- 睡觉定义 -->
<canLayDown>false</canLayDown>
<!-- 各种零件定义 -->
<alienPartGenerator Inherit="False">
<!-- 允许的头部 -->
<headTypes Inherit="False">
<li>Female_AverageNormal</li>
<!-- <li>Female_AverageWide</li>
<li>Female_AveragePointy</li> -->
</headTypes>
<!-- 身体类型 -->
<bodyTypes Inherit="False">
<li>Thin</li>
</bodyTypes>
<!-- 颜色设置 -->
<colorChannels Inherit="false">
<!-- 皮肤是特殊的,因为现在由基因定义肤色 -->
<li>
<name>skin</name>
<first Class="AlienRace.ColorGenerator_SkinColorMelanin">
<minMelanin>0</minMelanin>
<maxMelanin>0</maxMelanin>
</first>
</li>
<!-- 头发颜色 -->
<li>
<name>hair</name>
<first Class="ColorGenerator_Options">
<options>
<li>
<weight>15</weight>
<min>(0.4,0.3,0.5)</min>
<max>(0.6,0.1,0.7)</max>
</li>
<li>
<weight>6</weight>
<min>(0.9,0.9,0.9)</min>
<max>(0.9,0.9,0.9)</max>
</li>
<li>
<weight>6</weight>
<min>(1,0.8,0.8)</min>
<max>(1,0.9,0.9)</max>
</li>
<li>
<weight>3</weight>
<min>(1,1,1)</min>
<max>(1,1,1)</max>
</li>
</options>
</first>
</li>
</colorChannels>
<!-- 额外身体部件 -->
<bodyAddons>
</bodyAddons>
<!-- 图像放大 -->
<borderScale>4</borderScale>
<atlasScale>4</atlasScale>
<customDrawSize>(4,4)</customDrawSize>
<customHeadDrawSize>(1.0,1.0)</customHeadDrawSize>
<customPortraitDrawSize>(2,2)</customPortraitDrawSize>
</alienPartGenerator>
<growthAges Inherit="False">
<li>0</li>
</growthAges>
<!-- 年龄工作效率等的覆盖 -->
<ageStatOverrides Inherit="False">
<WorkSpeedGlobal>
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0,1)</li>
</points>
</curve>
</WorkSpeedGlobal>
<ShootingAccuracyChildFactor MayRequire="Ludeon.RimWorld.Biotech">
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0,1)</li>
</points>
</curve>
</ShootingAccuracyChildFactor>
<MarketValue>
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0,1)</li>
</points>
</curve>
</MarketValue>
<MeleeHitChance>
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0,1)</li>
</points>
</curve>
</MeleeHitChance>
<AimingDelayFactor>
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0,1)</li>
</points>
</curve>
</AimingDelayFactor>
<ArrestSuccessChance>
<useBiologicalYears>true</useBiologicalYears>
<curve>
<points>
<li>(0, 1)</li>
</points>
</curve>
</ArrestSuccessChance>
</ageStatOverrides>
<!-- 生育设置,将妊娠设为男性来避免开局刷妊娠 -->
<reproduction>
<gestatingGender>Male</gestatingGender>
<femaleFertilityAgeFactor>
<points>
<li>(0,0)</li>
<li>(1,0)</li>
<li>(999,0)</li>
<li>(9999,0)</li>
</points>
</femaleFertilityAgeFactor>
</reproduction>
<growthFactorByAge Inherit="False">
<points>
<li>(0,0)</li>
<li>(1,0)</li>
<li>(999,0)</li>
<li>(9999,0)</li>
</points>
</growthFactorByAge>
</generalSettings>
<!-- 图形 -->
<graphicPaths>
<!-- 皮肤颜色 -->
<skinColor>(1,1,1,1)</skinColor>
<!-- 皮肤着色器 -->
<skinShader>Cutout</skinShader>
<body>ArachnaeSwarm/Things/ARA_HiveQueen/Bodies/</body>
<head>ArachnaeSwarm/Things/ARA_HiveQueen/Heads/</head>
<skeleton>Things/Pawn/Humanlike/Bodies/Dessicated/Dessicated_Thin</skeleton>
<stump>ArachnaeSwarm/Things/ARA_HiveQueen/Bodies/</stump>
</graphicPaths>
<!-- 风格设置 -->
<styleSettings>
<!-- 头发 -->
<li>
<key>HairDef</key>
<value>
<hasStyle>true</hasStyle>
<styleTagsOverride>
<li>Bald</li>
</styleTagsOverride>
</value>
</li>
<!-- 纹身 -->
<li>
<key>TattooDef</key>
<value>
<hasStyle>false</hasStyle>
</value>
</li>
<!-- 胡须 -->
<li>
<key>BeardDef</key>
<value>
<hasStyle>false</hasStyle>
</value>
</li>
</styleSettings>
<!-- 种族的允许和禁止特化设置 -->
<raceRestriction>
<!-- 无法拥有的内源性基因 -->
<blackEndoCategories MayRequire="Ludeon.RimWorld.Biotech">
<li MayRequire="Ludeon.RimWorld.Biotech">HairColor</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Melanin</li>
<li MayRequire="Ludeon.RimWorld.Biotech">BodyType</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Ears</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Nose</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Voice</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Headbone</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Head</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Jaw</li>
</blackEndoCategories>
<!-- 无法拥有的Tag基因 -->
<blackGeneTags MayRequire="Ludeon.RimWorld.Biotech">
<li MayRequire="Ludeon.RimWorld.Biotech">EyeColor</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Tail</li>
<li MayRequire="Ludeon.RimWorld.Biotech">BeardStyle</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Fur</li>
</blackGeneTags>
<!-- 无法拥有的基因列表 -->
<blackGeneList>
<li MayRequire="Ludeon.RimWorld.Biotech">Furskin</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Brow_Heavy</li>
</blackGeneList>
<!-- 禁止的异形变种 -->
<blackXenotypeList>
<li MayRequire="Ludeon.RimWorld.Biotech">Dirtmole</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Genie</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Hussar</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Sanguophage</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Neanderthal</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Pigskin</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Impid</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Waster</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Yttakin</li>
<li MayRequire="Ludeon.RimWorld.Biotech">Highmate</li>
</blackXenotypeList>
<!-- 异种类型列表 -->
<xenotypeList>
</xenotypeList>
<onlyUseRaceRestrictedXenotypes>true</onlyUseRaceRestrictedXenotypes>
<!-- 食物列表 -->
<whiteFoodList>
<li>ARA_InsectJelly</li>
<li>ARA_NutrientPasteMeal</li>
<li>ARA_PheromoneSolvent</li>
</whiteFoodList>
<onlyEatRaceRestrictedFood>true</onlyEatRaceRestrictedFood>
<!-- 可以驯服的宠物,主要是防止小虫由别人驯服 -->
<petList>
<li>ArachnaeBase_Race_Scavenger</li>
<li>ArachnaeBase_Race_Larva</li>
</petList>
<onlyTameRaceRestrictedPets>true</onlyTameRaceRestrictedPets>
<!-- 可以穿戴的衣服 -->
<apparelList>
</apparelList>
<blackApparelList>
</blackApparelList>
<!-- 仅使用种族限制的服装 -->
<onlyUseRaceRestrictedApparel>true</onlyUseRaceRestrictedApparel>
<!-- 生育能力 -->
<onlyReproduceWithRestrictedRaces>true</onlyReproduceWithRestrictedRaces>
<canReproduce>false</canReproduce>
<!-- 允许操纵的配方 -->
<recipeList>
</recipeList>
<!-- <workGiverList>
</workGiverList> -->
<!-- 允许的特质类型 -->
<traitList>
</traitList>
<blackTraitList>
<li>BodyPurist</li>
<li>Cannibal</li>
<li>CreepyBreathing</li>
<li>DislikesWomen</li>
<li>Gourmand</li>
<li>QuickSleeper</li>
<li>Wimp</li>
<li>Beauty</li>
<li>DrugDesire</li>
<li>Immunity</li>
<li>PsychicSensitivity</li>
</blackTraitList>
</raceRestriction>
<!-- 想法设置 -->
<thoughtSettings>
<!-- 不会产生的想法 -->
<cannotReceiveThoughts>
<li>ColonistLost</li>
<li>KnowColonistDied</li>
<li>PawnWithGoodOpinionDied</li>
<li>PsychicDrone</li>
<li>Naked</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Female</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Male</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Memory</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Social_Female</li>
<li>AnyBodyPartButGroinCovered_Disapproved_Social_Male</li>
<li>AnyBodyPartCovered_Disapproved_Female</li>
<li>AnyBodyPartCovered_Disapproved_Male</li>
<li>AnyBodyPartCovered_Disapproved_Memory</li>
<li>AnyBodyPartCovered_Disapproved_Social_Female</li>
<li>AnyBodyPartCovered_Disapproved_Social_Male</li>
<li>GroinChestHairOrFaceUncovered_Disapproved_Female</li>
<li>GroinChestHairOrFaceUncovered_Disapproved_Male</li>
<li>GroinChestHairOrFaceUncovered_Disapproved_Social_Female</li>
<li>GroinChestHairOrFaceUncovered_Disapproved_Social_Male</li>
<li>GroinChestOrHairUncovered_Disapproved_Female</li>
<li>GroinChestOrHairUncovered_Disapproved_Male</li>
<li>GroinChestOrHairUncovered_Disapproved_Social_Female</li>
<li>GroinChestOrHairUncovered_Disapproved_Social_Male</li>
<li>GroinOrChestUncovered_Disapproved_Female</li>
<li>GroinOrChestUncovered_Disapproved_Male</li>
<li>GroinOrChestUncovered_Disapproved_Social_Female</li>
<li>GroinOrChestUncovered_Disapproved_Social_Male</li>
<li>GroinUncovered_Disapproved_Female</li>
<li>GroinUncovered_Disapproved_Male</li>
<li>GroinUncovered_Disapproved_Social_Female</li>
<li>GroinUncovered_Disapproved_Social_Male</li>
<li>WitnessedDeathAlly</li>
<li>ObservedLayingCorpse</li>
<li>ObservedLayingRottingCorpse</li>
<li>ApparelDamaged</li>
<li>ProsthophileHappy</li>
<li>ProsthophobeUnhappy</li>
<li>BrawlerUnhappy</li>
<li>PyromaniacHappy</li>
<li>Greedy</li>
<li>Jealous</li>
<li>SharedBed</li>
<li>AteWithoutTable</li>
<li>SleptOutside</li>
<li>SleptOnGround</li>
<li>SleptInCold</li>
<li>SleptInHeat</li>
<li>Ugly</li>
<li>AteKibble</li>
<li>AteInsectMeatDirect</li>
<li>AteInsectMeatAsIngredient</li>
<li>AteRawFood</li>
<li>AteHumanlikeMeatDirect</li>
<li>AteHumanlikeMeatAsIngredient</li>
<li>KnowButcheredHumanlikeCorpse</li>
<li>ButcheredHumanlikeCorpseOpinion</li>
<li>AteRawHumanlikeMeat</li>
</cannotReceiveThoughts>
<!-- 该种族特有想法 -->
<restrictedThoughts>
</restrictedThoughts>
</thoughtSettings>
<!-- 关系设置,不会生成任何随机关系 -->
<relationSettings>
<relationChanceModifierLover>0</relationChanceModifierLover>
<relationChanceModifierExLover>0</relationChanceModifierExLover>
<relationChanceModifierFiance>0</relationChanceModifierFiance>
<relationChanceModifierSpouse>0</relationChanceModifierSpouse>
<relationChanceModifierExSpouse>0</relationChanceModifierExSpouse>
<relationChanceModifierParent>0</relationChanceModifierParent>
<relationChanceModifierChild>0</relationChanceModifierChild>
<relationChanceModifierSibling>0</relationChanceModifierSibling>
</relationSettings>
</alienRace>
<recipes Inherit="False">
<li>ARA_CureBloodRot</li>
<li>ARA_CureAcid</li>
<li>RemovePorcupineQuill</li>
<li>SurgicalInspection</li>
<li>ARA_Surgery_Install_Plasteel</li>
<li>ARA_Surgery_Install_Carapace_Shell</li>
<li>ARA_Surgery_Install_Huge_Stomach</li>
<li>ARA_Surgery_Install_Cycle_Suppression</li>
<li>ARA_Surgery_Install_Shell_Thorn</li>
<li>ARA_Surgery_Install_Reactive_Shell</li>
<li>ARA_Surgery_Install_Strengthening_Tendon</li>
<li>ARA_Surgery_Install_Slide_Patagium</li>
<li>ARA_Surgery_Install_Baneling_Pouch</li>
<li>ARA_Surgery_Install_Tumor_Pouch</li>
<li>ARA_Surgery_Install_Internal_Circulation_Lung</li>
</recipes>
<!-- 基础属性设置 -->
<statBases>
<!-- 市场价值 -->
<MarketValue>2000</MarketValue>
<RoyalFavorValue>5</RoyalFavorValue>
<!-- 移动速度 -->
<MoveSpeed>1.75</MoveSpeed>
<Mass>250</Mass>
<!-- <RestRateMultiplier>1</RestRateMultiplier> -->
<!-- <HungerRateMultiplier>1</HungerRateMultiplier> -->
<EatingSpeed>2</EatingSpeed>
<!-- 女皇很长时间才需要补充一次食物 -->
<MaxNutrition>0.5</MaxNutrition>
<!-- 女皇的负重,设为0以避免女皇能背东西 -->
<CarryingCapacity>200</CarryingCapacity>
<MeatAmount>450</MeatAmount>
<LeatherAmount>600</LeatherAmount>
<!-- 疼痛休克,女皇很难因为疼痛而倒下,虽并不是像机器人一样不会休克 -->
<PainShockThreshold>1</PainShockThreshold>
<!-- 女皇非常擅长灵能,以维持蜂群的蜂巢意识链接 -->
<PsychicSensitivity>2.5</PsychicSensitivity>
<!-- 女皇的崩溃概率 -->
<MentalBreakThreshold>0</MentalBreakThreshold>
<!-- 女皇的高耸身躯和强健循环系统使得很难被毒倒下 -->
<ToxicResistance>0.95</ToxicResistance>
<ToxicEnvironmentResistance MayRequire="Ludeon.RimWorld.Biotech">0.95</ToxicEnvironmentResistance>
<!-- 女皇的甲壳可以抵御火焰侵袭,难以燃烧-->
<Flammability>0.1</Flammability>
<!-- 女皇的庞大申请很难闪开近战 -->
<MeleeDodgeChance>0.25</MeleeDodgeChance>
<!-- <MeleeHitChance>1</MeleeHitChance> -->
<!-- <NegotiationAbility>1</NegotiationAbility> -->
<!-- <SellPriceFactor>1</SellPriceFactor> -->
<!-- <SocialImpact>1</SocialImpact> -->
<!-- <TradePriceImprovement>0.5</TradePriceImprovement> -->
<!-- 自带的甲壳可以防御外部攻击 -->
<ArmorRating_Blunt>0.6</ArmorRating_Blunt>
<ArmorRating_Sharp>0.8</ArmorRating_Sharp>
<ArmorRating_Heat>0.5</ArmorRating_Heat>
<!-- 虫群拥有惊人的愈合速度 -->
<InjuryHealingFactor>5</InjuryHealingFactor>
<!-- 在野外采集的营养 -->
<ForagedNutritionPerDay>0</ForagedNutritionPerDay>
<ARA_GestaltBandwidth>15</ARA_GestaltBandwidth>
<MechControlGroups>1</MechControlGroups>
</statBases>
<race>
<!-- 身体类型 -->
<body>ArachnaeQueen_Body</body>
<fleshType>Normal</fleshType>
<!-- AI行为勿改 -->
<thinkTreeMain>ARA_Humanlike</thinkTreeMain>
<!-- 智力水平 -->
<intelligence>Humanlike</intelligence>
<!-- 肉和皮革的定义 -->
<nameCategory>HumanStandard</nameCategory>
<bloodDef>Filth_BloodInsect</bloodDef>
<bloodSmearDef>Filth_BloodSmear</bloodSmearDef>
<!-- 身形大小 -->
<baseBodySize>10</baseBodySize>
<!-- 基础血量,很高 -->
<baseHealthScale>10</baseHealthScale>
<!-- 解剖产物 -->
<leatherDef>ARA_Carapace</leatherDef>
<soundMeleeHitPawn>Pawn_Melee_BigBash_HitPawn</soundMeleeHitPawn>
<soundMeleeHitBuilding>Pawn_Melee_BigBash_HitBuilding</soundMeleeHitBuilding>
<soundMeleeMiss>Pawn_Melee_BigBash_Miss</soundMeleeMiss>
<soundMeleeDodge>Pawn_MeleeDodge</soundMeleeDodge>
<!-- 年龄阶段 -->
<lifeExpectancy>300</lifeExpectancy>
<lifeStageWorkSettings MayRequire="Ludeon.RimWorld.Biotech" Inherit="False">
<Firefighter>0</Firefighter>
<Patient>0</Patient>
<Doctor>0</Doctor>
<PatientBedRest>0</PatientBedRest>
<Childcare MayRequire="Ludeon.RimWorld.Biotech">0</Childcare>
<BasicWorker>0</BasicWorker>
<Warden>0</Warden>
<Handling>0</Handling>
<Cooking>0</Cooking>
<Hunting>0</Hunting>
<Construction>0</Construction>
<Growing>0</Growing>
<Mining>0</Mining>
<PlantCutting>0</PlantCutting>
<Smithing>0</Smithing>
<Tailoring>0</Tailoring>
<Art>0</Art>
<Crafting>0</Crafting>
<Hauling>0</Hauling>
<Cleaning>0</Cleaning>
<Research>0</Research>
<DarkStudy MayRequire="Ludeon.RimWorld.Anomaly">0</DarkStudy>
</lifeStageWorkSettings>
<lifeStageAges Inherit="False">
<li>
<def>HumanlikeBaby</def>
<minAge>0</minAge>
</li>
<li>
<def>HumanlikeChild</def>
<minAge>0.25</minAge>
</li>
<li MayRequire="Ludeon.RimWorld.Biotech">
<def>HumanlikePreTeenager</def>
<minAge>0.5</minAge>
</li>
<li>
<def>HumanlikeTeenager</def>
<minAge>0.75</minAge>
</li>
<li>
<def>HumanlikeAdult</def>
<minAge>1</minAge>
<soundWounded>Pawn_HiveQueen_Wounded</soundWounded>
<soundDeath>Pawn_HiveQueen_Death</soundDeath>
<soundCall>Pawn_HiveQueen_Call</soundCall>
<soundAngry>Pawn_HiveQueen_Angry</soundAngry>
</li>
</lifeStageAges>
<canFlyInVacuum>false</canFlyInVacuum>
</race>
<comps>
<li Class="ArachnaeSwarm.CompProperties_UniquePawn">
<globalVariable>Unique_Arachnae_Queen</globalVariable>
<showDeathMessage>true</showDeathMessage>
<deathMessageKey>ARA_QueenAlreadyExists</deathMessageKey>
<!-- <killDamageDef>AcidBurn</killDamageDef> -->
</li>
<li Class="ArachnaeSwarm.CompProperties_HediffGiver">
<hediffs>
<li>ARA_HiveStrength</li>
<li>ARA_HiveMindMaster</li>
</hediffs>
<addChance>1.0</addChance>
<allowDuplicates>false</allowDuplicates>
</li>
<li Class="ArachnaeSwarm.CompProperties_Gestalt" />
</comps>
</AlienRace.ThingDef_AlienRace>
<AlienRace.ThingDef_AlienRace ParentName="ARA_QueenBase">
<defName>ArachnaeQueen_Race_Titan</defName>
<label>阿拉克涅泰坦种</label>
<description>阿拉克涅泰坦种是女皇种亚种之一,归属于阿拉克涅的泰坦触须。她们指挥着阿拉克涅虫群中最坚韧、最强大的主力集团,承担在战场上正面</description>
<description>阿拉克涅泰坦种是女皇种亚种之一,归属于阿拉克涅的泰坦触须。她们指挥着阿拉克涅虫群中最坚韧、最具有适应力的主力集团族群,承担在战场上维持战线的任务。\n\n泰坦种女皇除了可以提供泰坦触须的独特科技外自身也有强大的甲壳作为防御层还可以通过践踏和高额的近战伤害攻击靠近的敌人。</description>
<statBases>
<MarketValue>2000</MarketValue>
<MoveSpeed>1.75</MoveSpeed>
<Mass>250</Mass>
<CarryingCapacity>200</CarryingCapacity>
<MeatAmount>450</MeatAmount>
<LeatherAmount>600</LeatherAmount>
<PainShockThreshold>1</PainShockThreshold>
<PsychicSensitivity>2.5</PsychicSensitivity>
<ToxicResistance>0.95</ToxicResistance>
<ToxicEnvironmentResistance MayRequire="Ludeon.RimWorld.Biotech">0.95</ToxicEnvironmentResistance>
<Flammability>0.1</Flammability>
<MeleeDodgeChance>0.25</MeleeDodgeChance>
<ArmorRating_Blunt>0.6</ArmorRating_Blunt>
<ArmorRating_Sharp>0.8</ArmorRating_Sharp>
<ArmorRating_Heat>0.5</ArmorRating_Heat>
<ARA_GestaltBandwidth>12</ARA_GestaltBandwidth>
<MechControlGroups>1</MechControlGroups>
</statBases>
<!-- 工具设置(攻击方式) -->
<tools>
<li>
<label>头顶</label>
<capacities>
<li>Poke</li>
</capacities>
<power>16</power>
<cooldownTime>2</cooldownTime>
<linkedBodyPartsGroup>HeadAttackTool</linkedBodyPartsGroup>
<ensureLinkedBodyPartsGroupAlwaysUsable>true</ensureLinkedBodyPartsGroupAlwaysUsable>
<chanceFactor>0.01</chanceFactor>
</li>
<li>
<label>踩踏</label>
<capacities>
<li>Blunt</li>
<li>Poke</li>
</capacities>
<power>35</power>
<cooldownTime>2.5</cooldownTime>
<linkedBodyPartsGroup>Legs</linkedBodyPartsGroup>
</li>
<li>
<label>腿部穿刺</label>
<capacities>
<li>Stab</li>
</capacities>
<power>50</power>
<cooldownTime>3</cooldownTime>
<linkedBodyPartsGroup>Legs</linkedBodyPartsGroup>
</li>
<li>
<label>钳击</label>
<capacities>
<li>Cut</li>
</capacities>
<power>30</power>
<cooldownTime>2</cooldownTime>
<linkedBodyPartsGroup>Hands</linkedBodyPartsGroup>
</li>
</tools>
<comps>
<li Class="ArachnaeSwarm.CompProperties_AutoMechCarrier">
<freeProduction>true</freeProduction>
<disableHediff>ARA_RaceBaseSwarmProduceSwitchHediff</disableHediff>
<spawnEffecter>CocoonDestroyed</spawnEffecter>
</li>
<li Class="ArachnaeSwarm.CompProperties_AreaDamage">
<radius>3</radius>
<damageIntervalTicks>180</damageIntervalTicks>
<damageDef>Crush</damageDef>
<damageAmount>10</damageAmount>
<scaleWithPsychicSensitivity>false</scaleWithPsychicSensitivity>
<areaEffecterDef>ARA_Area_Crush</areaEffecterDef>
<startEnabled>false</startEnabled>
<toggleLabel>践踏</toggleLabel>
<toggleDescription>这只阿拉克涅虫族的身躯是如此巨大,以至于靠近它的敌人会被直接一脚踩死</toggleDescription>
<toggleIconPath>ArachnaeSwarm/UI/Abilities/ARA_Area_Crush</toggleIconPath>
</li>
</comps>
</AlienRace.ThingDef_AlienRace>
<AlienRace.ThingDef_AlienRace Name="ARA_QueenBase" ParentName="ARA_PawnBase">
<defName>ArachnaeQueen_Race_Neurotyrant</defName>
<label>阿拉克涅灵吸种</label>
<description>阿拉克涅灵吸种是女皇种亚种之一,归属于阿拉克涅的灵能触须。她们负责维持虫族蜂巢灵能网路的通讯,并作为中继节点链接各战区女皇种和虫巢舰队。\n\n但是灵吸种可不是脆弱的“文官”她们强大的灵能使得她们可以通过超自然力量主宰当地战局随着她们不断吞噬本地物种其灵能能力还能得到不断的进化。</description>
<alienRace>
<!-- 核心设置 -->

View File

@@ -68,7 +68,7 @@
<li>ArachnaeNode_Race_Skyraider</li>
<li>ArachnaeNode_Race_NeuroSwarm</li>
<li>ArachnaeNode_Race_Praetorian</li>
<li>ArachnaeQueen_Race</li>
<li>ArachnaeQueen_Race_Titan</li>
</targetRaces>
</li>
</outcomeDoers>

View File

@@ -95,7 +95,7 @@
<label>阿拉克涅女皇种卵囊</label>
<description>用于孵化阿拉克涅女皇种的超巨型卵囊,表皮坚硬地堪比堡垒,内部蕴含的遗传物质和营养足以孵化出这个星球闻所未闻的庞然大物。</description>
<descriptionHyperlinks>
<ThingDef>ArachnaeQueen_Race</ThingDef>
<ThingDef>ArachnaeQueen_Race_Titan</ThingDef>
</descriptionHyperlinks>
<graphicData>
<color>(0.9, 0.9 ,0.5)</color>

View File

@@ -757,6 +757,45 @@
</thinkRoot>
</ThinkTreeDef>
<ThinkTreeDef>
<defName>ARA_Insect_Thinktree_Constant</defName>
<thinkRoot Class="ThinkNode_Priority">
<subNodes>
<!-- Despawned -->
<li Class="ThinkNode_Subtree">
<treeDef>Despawned</treeDef>
</li>
<li Class="ThinkNode_ConditionalCanDoConstantThinkTreeJobNow">
<subNodes>
<!-- Flee explosion -->
<li Class="JobGiver_FleePotentialExplosion" />
<!-- Avoid vacuums -->
<li Class="JobGiver_FindOxygen" />
<!-- Board/leave gravship -->
<li Class="JobGiver_BoardOrLeaveGravship" />
<!-- Join auto joinable caravan -->
<li Class="ThinkNode_Subtree">
<treeDef>JoinAutoJoinableCaravan</treeDef>
</li>
</subNodes>
</li>
<li Class="ThinkNode_ConditionalCanDoLordJobNow">
<subNodes>
<!-- Lord directives -->
<li Class="ThinkNode_Subtree">
<treeDef>LordDutyConstant</treeDef>
</li>
</subNodes>
</li>
</subNodes>
</thinkRoot>
</ThinkTreeDef>
<ThinkTreeDef>
<defName>ARA_Insect_Larva_Thinktree</defName>
<thinkRoot Class="ThinkNode_Priority">
@@ -784,12 +823,18 @@
<treeDef>MentalStateCritical</treeDef>
</li>
<!-- React to close melee threat -->
<li Class="JobGiver_ReactToCloseMeleeThreat"/>
<!-- Do a queued job -->
<li Class="ThinkNode_QueuedJob"/>
<li Class="ThinkNode_JoinVoluntarilyJoinableLord">
<dutyHook>HighPriority</dutyHook>
<subNodes>
<li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</subNodes>
</li>
<!-- Mental state non critical -->
<li Class="ThinkNode_Subtree">
<treeDef>MentalStateNonCritical</treeDef>
@@ -811,11 +856,10 @@
<li Class="ThinkNode_Subtree">
<treeDef>RopedPawn</treeDef>
</li>
<!-- Lord directives -->
<li Class="ThinkNode_Subtree">
<!-- <li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</li> -->
<li Class="ThinkNode_ConditionalHasFaction">
<invert>true</invert>
@@ -883,6 +927,16 @@
<treeDef>SatisfyBasicNeeds</treeDef>
</li>
<!-- Lord directives (medium priority) -->
<li Class="ThinkNode_JoinVoluntarilyJoinableLord">
<dutyHook>MediumPriority</dutyHook>
<subNodes>
<li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</subNodes>
</li>
<!-- Tame animal: wander near colony if possible -->
<li Class="ThinkNode_ConditionalOfPlayerFaction">
<subNodes>
@@ -1012,6 +1066,15 @@
<!-- Do a queued job -->
<li Class="ThinkNode_QueuedJob"/>
<li Class="ThinkNode_JoinVoluntarilyJoinableLord">
<dutyHook>HighPriority</dutyHook>
<subNodes>
<li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</subNodes>
</li>
<!-- Mental state non critical -->
<li Class="ThinkNode_Subtree">
<treeDef>MentalStateNonCritical</treeDef>
@@ -1035,9 +1098,9 @@
</li>
<!-- Lord directives -->
<li Class="ThinkNode_Subtree">
<!-- <li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</li> -->
<li Class="ThinkNode_ConditionalHasFaction">
<invert>true</invert>
@@ -1170,6 +1233,16 @@
<treeDef>SatisfyBasicNeeds</treeDef>
</li>
<!-- Lord directives (medium priority) -->
<li Class="ThinkNode_JoinVoluntarilyJoinableLord">
<dutyHook>MediumPriority</dutyHook>
<subNodes>
<li Class="ThinkNode_Subtree">
<treeDef>LordDuty</treeDef>
</li>
</subNodes>
</li>
<!-- Tame insect: do useful things for the colony-->
<li Class="ThinkNode_ConditionalHasFaction">
<subNodes>

View File

@@ -1,92 +1,7 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comprefuelablenutrition.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_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|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_compinteractiveproducer\\compinteractiveproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_compinteractiveproducer\\compinteractiveproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_transformcorpse.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\\buildings\\building_ootheca\\gizmo_pawnprogressbar.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_pawnprogressbar.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\\gizmo_neutronflux.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_neutronflux.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_configurablemutant\\necrotictransformationutility.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_configurablemutant\\necrotictransformationutility.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_nodeswarmlifetime\\compnodeswarmlifetime.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_nodeswarmlifetime\\compnodeswarmlifetime.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\\gizmo_queuedincubationprogress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\gizmo_queuedincubationprogress.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}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\building_equipmentootheca.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\\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_plant\\jobgiver_grower.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_plant\\jobgiver_grower.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_clean\\jobgiver_cleaner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_clean\\jobgiver_cleaner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_huggingface\\hediff_possession.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_huggingface\\hediff_possession.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_huggingface\\compabilityeffect_possess.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_huggingface\\compabilityeffect_possess.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_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.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_hediffterrainspawn\\compproperties_hediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffterrainspawn\\compproperties_hediffterrainspawn.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_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffterrainspawn\\comphediffterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
@@ -94,271 +9,11 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 6,
"SelectedChildIndex": -1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CompRefuelableNutrition.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeDocumentMoniker": "Building_Comps\\CompRefuelableNutrition.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeToolTip": "Building_Comps\\CompRefuelableNutrition.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAyAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:40.77Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"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": "AgIAAAAAAAAAAAAAAAAAAAUAAABKAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:33.86Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "CompInteractiveProducer.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"RelativeToolTip": "Building_Comps\\ARA_CompInteractiveProducer\\CompInteractiveProducer.cs",
"ViewState": "AgIAAFICAAAAAAAAAAAAAFICAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:32.573Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "CompAbilityEffect_TransformCorpse.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeToolTip": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ViewState": "AgIAAFQAAAAAAAAAAAAuwGkAAABdAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T03:51:29.604Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"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": "AgIAAAAAAAAAAAAAAAAAABQAAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-27T00:51:15.459Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Building_Ootheca.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ViewState": "AgIAABwCAAAAAAAAAAAvwDICAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:31:14.555Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "NecroticTransformationUtility.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"RelativeToolTip": "Hediffs\\ARA_ConfigurableMutant\\NecroticTransformationUtility.cs",
"ViewState": "AgIAAA8AAAAAAAAAAAAtwCIAAAAcAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:44:42.184Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "CompNodeSwarmLifetime.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"RelativeToolTip": "Pawn_Comps\\ARA_NodeSwarmLifetime\\CompNodeSwarmLifetime.cs",
"ViewState": "AgIAADYAAAAAAAAAAAAtwEoAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:44:35.266Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "Gizmo_QueuedIncubationProgress.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_QueuedIncubationProgress.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:11:04.23Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "Gizmo_PawnProgressBar.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_PawnProgressBar.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAAAFAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:12:03.772Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "Gizmo_NeutronFlux.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Gizmo_NeutronFlux.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAAiAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T08:11:53.324Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 11,
"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": "AgIAAEIBAAAAAAAAAAAAAEMBAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-26T07:52:41.869Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"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": "AgIAAAAAAAAAAAAAAAAAAAgAAAASAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T10:24:46.264Z"
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "JobGiver_Grower.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"RelativeToolTip": "Jobs\\JobDriver_Plant\\JobGiver_Grower.cs",
"ViewState": "AgIAAFMAAAAAAAAAAAAQwGkAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:51:03.439Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "Hediff_Possession.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"RelativeToolTip": "Abilities\\ARA_HuggingFace\\Hediff_Possession.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:50:05.221Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "CompAbilityEffect_Possess.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"RelativeToolTip": "Abilities\\ARA_HuggingFace\\CompAbilityEffect_Possess.cs",
"ViewState": "AgIAAHcAAAAAAAAAAAAAAIkAAAA5AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:50:01.549Z"
},
{
"$type": "Document",
"DocumentIndex": 13,
"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": "AgIAAAAAAAAAAAAAAADwvx0AAAAoAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T10:25:01.777Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "CompDelayedTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeToolTip": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ViewState": "AgIAAFEAAAAAAAAAAAAAAF8AAAA+AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:46:06.784Z"
},
{
"$type": "Document",
"DocumentIndex": 19,
"Title": "CompProperties_HediffTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"RelativeToolTip": "Hediffs\\ARA_HediffTerrainSpawn\\CompProperties_HediffTerrainSpawn.cs",
"ViewState": "AgIAAAUAAAAAAAAAAAAtwBkAAAAxAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:44:14.682Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "JobGiver_Cleaner.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"RelativeToolTip": "Jobs\\JobDriver_Clean\\JobGiver_Cleaner.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAABwAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:51:58.899Z"
},
{
"$type": "Document",
"DocumentIndex": 20,
"Title": "CompHediffTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"RelativeToolTip": "Hediffs\\ARA_HediffTerrainSpawn\\CompHediffTerrainSpawn.cs",
"ViewState": "AgIAAKIAAAAAAAAAAAAawLQAAAAMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-01-23T08:44:10.075Z"
}
]
}

View File

@@ -334,6 +334,7 @@
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProducedByMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_ProducedByMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\IBidirectionalValidator.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\PawnProductionEntry.cs" />
<Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompHediffGiver.cs" />
<Compile Include="Pawn_Comps\ARA_CompHediffGiver\CompProperties_HediffGiver.cs" />

View File

@@ -561,20 +561,30 @@ namespace ArachnaeSwarm
}
public override IEnumerable<Gizmo> GetGizmos()
{
base.GetGizmos();
foreach (var gizmo in base.GetGizmos())
{
if (gizmo is Command_Action cmd && cmd.defaultLabel != null)
{
string label = cmd.defaultLabel.ToString();
if (label.Contains("拆除") || label.Contains("Deconstruct") || label.Contains("半径") || label.Contains("Radius"))
continue;
}
// 强制将基础组件(如 Refuelable甚至默认排序为 -100 的东西移到后面
if (gizmo.Order >= -100f && gizmo.Order <= 0f)
{
gizmo.Order = -90f;
}
yield return gizmo;
}
// 首先获取选中的同类建筑
var selectedOothecas = GetSelectedOothecas();
bool isMultiSelect = selectedOothecas.Count > 1;
if (Faction == Faction.OfPlayer)
{
// 在多选时,只在第一个建筑上显示进度条和通量条
if (!isMultiSelect || (isMultiSelect && selectedOothecas.First() == this))
{
yield return new Gizmo_PawnProgressBar(this);
yield return new Gizmo_NeutronFlux(this);
}
var config = IncubatorData?.SelectedConfig;
// 添加订单按钮(多选时合并)
@@ -657,6 +667,7 @@ namespace ArachnaeSwarm
}
}
}
/// <summary>
/// 为多选建筑显示订单菜单
/// </summary>

View File

@@ -1,4 +1,6 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.AI;
@@ -14,6 +16,12 @@ namespace ArachnaeSwarm
// 是否仅防御征召状态的生产者针对pawn类型生产者
public bool onlyDefendDrafted = true;
// 是否排除休眠的机械族
public bool excludeDormantMechs = true;
// 是否将炮塔纳入考虑
public bool includeHostileTurrets = true;
protected override Pawn GetDefendee(Pawn pawn)
{
// 我们不需要返回Pawn类型的防御者因为我们实际上防御的是Thing
@@ -79,7 +87,7 @@ namespace ArachnaeSwarm
float defendRadiusValue = GetFlagRadius(pawn);
// 寻找附近的威胁
Pawn enemy = FindEnemy(pawn, defendRadiusValue);
Thing enemy = FindEnemy(pawn, defendRadiusValue);
if (enemy != null)
{
// 创建攻击工作
@@ -94,7 +102,8 @@ namespace ArachnaeSwarm
return null;
}
private Pawn FindEnemy(Pawn pawn, float radius)
protected virtual Thing FindEnemy(Pawn pawn, float radius)
{
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producerComp == null || !producerComp.HasValidProducer)
@@ -103,10 +112,10 @@ namespace ArachnaeSwarm
Thing producer = producerComp.Producer;
IntVec3 center = producer.Position;
return (Pawn)AttackTargetFinder.BestAttackTarget(
return (Thing)AttackTargetFinder.BestAttackTarget(
pawn,
TargetScanFlags.NeedLOSToAll,
target => target is Pawn p && pawn.HostileTo(p) && p.Spawned && !p.Downed && !p.Dead,
TargetScanFlags.NeedThreat,
(Thing x) => ExtraTargetValidator(pawn, x),
0f,
radius,
center,
@@ -121,6 +130,9 @@ namespace ArachnaeSwarm
JobGiver_AIDefendProducer obj = (JobGiver_AIDefendProducer)base.DeepCopy(resolve);
obj.attackMeleeThreatEvenIfNotHostile = attackMeleeThreatEvenIfNotHostile;
obj.defendRadius = defendRadius;
obj.onlyDefendDrafted = onlyDefendDrafted;
obj.excludeDormantMechs = excludeDormantMechs;
obj.includeHostileTurrets = includeHostileTurrets;
return obj;
}

View File

@@ -10,18 +10,6 @@ namespace ArachnaeSwarm
/// </summary>
public class ThinkNode_ConditionalNotProducedByMechCarrier : ThinkNode_Conditional
{
// 可选:是否检查生产者是否存活
private bool checkProducerAlive = true;
// 可选:是否检查生产者是否在同一地图
private bool checkSameMap = false;
// 可选:是否检查生产者是否可到达
private bool checkReachable = false;
// 可选是否检查生产者类型pawn必须征召才跟随
private bool checkProducerTypeConditions = true;
public ThinkNode_ConditionalNotProducedByMechCarrier()
{
}
@@ -29,7 +17,7 @@ namespace ArachnaeSwarm
protected override bool Satisfied(Pawn pawn)
{
// 基础检查如果不是生产者生产的返回true
bool isProduced = IsProducedByMechCarrier(pawn);
bool isProduced = HasProducer(pawn);
// 如果是生产者生产的,再检查其他条件
if (isProduced)
@@ -44,7 +32,7 @@ namespace ArachnaeSwarm
/// <summary>
/// 检查pawn是否由生产者生产
/// </summary>
private bool IsProducedByMechCarrier(Pawn pawn)
private bool HasProducer(Pawn pawn)
{
if (!pawn.Spawned)
return false;
@@ -58,33 +46,6 @@ namespace ArachnaeSwarm
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;
}
}

View File

@@ -9,48 +9,63 @@ using Verse.AI.Group;
namespace ArachnaeSwarm
{
public class CompAutoMechCarrier : CompMechCarrier
public class CompAutoMechCarrier : CompMechCarrier, IBidirectionalValidator
{
#region Reflected Fields
private static FieldInfo spawnedPawnsField;
private static FieldInfo cooldownTicksRemainingField;
private static FieldInfo innerContainerField;
// 安全锁
private object validationLock = new object();
private List<Pawn> SpawnedPawns
{
get
{
lock (validationLock)
{
if (spawnedPawnsField == null)
spawnedPawnsField = typeof(CompMechCarrier).GetField("spawnedPawns", BindingFlags.NonPublic | BindingFlags.Instance);
return (List<Pawn>)spawnedPawnsField.GetValue(this);
}
}
}
private int CooldownTicksRemaining
{
get
{
lock (validationLock)
{
if (cooldownTicksRemainingField == null)
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
return (int)cooldownTicksRemainingField.GetValue(this);
}
}
set
{
lock (validationLock)
{
if (cooldownTicksRemainingField == null)
cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
cooldownTicksRemainingField.SetValue(this, value);
}
}
}
private ThingOwner InnerContainer
{
get
{
lock (validationLock)
{
if (innerContainerField == null)
innerContainerField = typeof(CompMechCarrier).GetField("innerContainer", BindingFlags.NonPublic | BindingFlags.Instance);
return (ThingOwner)innerContainerField.GetValue(this);
}
}
}
#endregion
#region Custom Follow Position
@@ -60,7 +75,6 @@ namespace ArachnaeSwarm
/// <summary>
/// 获取或设置自定义跟随位置
/// 如果此位置不为空,生成的单位将以此位置而非父单位位置为跟随中心点
/// </summary>
public IntVec3? CustomFollowPosition
{
@@ -85,14 +99,13 @@ namespace ArachnaeSwarm
customFollowPositionMap = null;
}
// 通知所有已生成的单位更新他们的跟随位置
NotifyFollowPositionChanged();
}
}
}
/// <summary>
/// 检查自定义位置是否有效(位置不为空且在正确的地图上)
/// 检查自定义位置是否有效
/// </summary>
public bool HasValidCustomFollowPosition
{
@@ -101,7 +114,6 @@ namespace ArachnaeSwarm
if (!customFollowPosition.HasValue || customFollowPositionMap == null)
return false;
// 如果父单位已销毁或不在同一地图,自定义位置也无效
if (parent == null || parent.Destroyed || !parent.Spawned)
return false;
@@ -111,7 +123,6 @@ namespace ArachnaeSwarm
/// <summary>
/// 获取有效的跟随位置
/// 优先返回自定义位置,如果无效则返回父单位位置
/// </summary>
public IntVec3 GetEffectiveFollowPosition()
{
@@ -120,7 +131,6 @@ namespace ArachnaeSwarm
return customFollowPosition.Value;
}
// 返回父单位位置
if (parent != null && parent.Spawned)
{
if (parent is Building building)
@@ -156,19 +166,16 @@ namespace ArachnaeSwarm
/// </summary>
private void NotifyFollowPositionChanged()
{
if (SpawnedPawns == null || !SpawnedPawns.Any())
var spawned = GetSafeSpawnedPawns();
if (spawned == null || !spawned.Any())
return;
// 清理无效的Pawn引用
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
// 通知每个Pawn的CompProducedByMechCarrier
foreach (Pawn spawnedPawn in SpawnedPawns)
foreach (var pawn in spawned)
{
if (spawnedPawn == null || spawnedPawn.Destroyed || !spawnedPawn.Spawned)
if (pawn == null || pawn.Destroyed || !pawn.Spawned)
continue;
var producedComp = spawnedPawn.TryGetComp<CompProducedByMechCarrier>();
var producedComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producedComp != null)
{
producedComp.TryUpdateProducerStatus();
@@ -187,8 +194,6 @@ namespace ArachnaeSwarm
/// <summary>
/// 设置自定义跟随位置
/// </summary>
/// <param name="position">新的跟随位置</param>
/// <returns>是否设置成功</returns>
public bool SetCustomFollowPosition(IntVec3 position)
{
if (parent == null || !parent.Spawned)
@@ -202,23 +207,18 @@ namespace ArachnaeSwarm
}
/// <summary>
/// 临时设置自定义跟随位置(在一段时间后自动清除)
/// 临时设置自定义跟随位置
/// </summary>
/// <param name="position">临时位置</param>
/// <param name="durationTicks">持续时间tick</param>
public void SetTemporaryFollowPosition(IntVec3 position, int durationTicks)
{
if (!SetCustomFollowPosition(position))
return;
// 启动定时器清除临时位置
StartPositionClearTimer(durationTicks);
}
private void StartPositionClearTimer(int durationTicks)
{
// 这里可以使用TickManager来安排定时清除
// 简单实现记录时间并在Tick中检查
temporaryPositionExpiryTick = Find.TickManager.TicksGame + durationTicks;
}
#endregion
@@ -238,35 +238,245 @@ namespace ArachnaeSwarm
}
#endregion
#region
// 子单位死亡通知队列
private Queue<Thing> childDeathQueue = new Queue<Thing>();
private int lastChildCleanupTick = -1;
private const int CHILD_CLEANUP_INTERVAL = 30;
// 已验证的子单位缓存
private HashSet<Thing> validatedChildren = new HashSet<Thing>();
private int lastValidationCacheClearTick = -1;
private const int VALIDATION_CACHE_CLEAR_INTERVAL = 300;
#endregion
#region IBidirectionalValidator
public bool IsProducerValid
{
get
{
lock (validationLock)
{
if (parent == null || parent.Destroyed)
return false;
if (parent is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
}
}
public Thing GetProducer()
{
lock (validationLock)
{
return IsProducerValid ? parent : null;
}
}
public bool IsProducerAlive
{
get
{
lock (validationLock)
{
return IsProducerValid && parent.Spawned;
}
}
}
public bool IsChildValid(Thing child)
{
if (child == null || child.Destroyed)
return false;
if (!(child is Pawn))
return false;
if (child is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
public bool IsChildAlive(Thing child)
{
return IsChildValid(child) && child.Spawned;
}
public bool ValidateBidirectional(Thing child)
{
lock (validationLock)
{
if (!IsProducerValid)
return false;
if (!IsChildValid(child))
return false;
return ValidateBidirectionalReference(child);
}
}
public bool ValidateAndExecute(Thing child, System.Action action)
{
if (!ValidateBidirectional(child))
return false;
try
{
action?.Invoke();
return true;
}
catch (System.Exception ex)
{
Log.Error($"生产者双向验证执行失败: {ex.Message}");
return false;
}
}
private bool ValidateBidirectionalReference(Thing child)
{
if (validatedChildren.Contains(child))
return true;
var spawned = GetSafeSpawnedPawns();
bool isInList = spawned.Contains(child as Pawn);
var childComp = (child as Pawn)?.TryGetComp<CompProducedByMechCarrier>();
bool hasValidReference = childComp != null && childComp.IsProducerValid && childComp.GetProducer() == parent;
bool isValid = isInList && hasValidReference;
if (isValid)
{
validatedChildren.Add(child);
}
return isValid;
}
/// <summary>
/// 验证子单位引用
/// </summary>
public bool ValidateChildReference(Thing child)
{
return ValidateBidirectionalReference(child);
}
/// <summary>
/// 通知子单位死亡
/// </summary>
public void NotifyChildDeath(Thing child)
{
lock (validationLock)
{
childDeathQueue.Enqueue(child);
}
}
/// <summary>
/// 安全移除子单位
/// </summary>
private void RemoveChildSafe(Thing child)
{
lock (validationLock)
{
try
{
var spawned = SpawnedPawns;
if (spawned != null && child is Pawn pawn)
{
bool removed = spawned.Remove(pawn);
if (removed && AutoProps.debugLogging)
{
Log.Message($"安全移除子单位: {pawn.LabelCap}");
}
}
validatedChildren.Remove(child);
}
catch (System.Exception ex)
{
Log.Error($"移除子单位失败: {ex.Message}");
}
}
}
/// <summary>
/// 清理无效的子单位引用
/// </summary>
private void CleanupInvalidChildren()
{
lock (validationLock)
{
// 处理死亡通知队列
while (childDeathQueue.Count > 0)
{
var deadChild = childDeathQueue.Dequeue();
if (deadChild != null)
{
RemoveChildSafe(deadChild);
}
}
// 清理spawnedPawns列表
var spawned = SpawnedPawns;
if (spawned != null)
{
int before = spawned.Count;
spawned.RemoveAll(p => p == null || p.Destroyed || (p is Pawn pawn && pawn.Dead));
if (before != spawned.Count && AutoProps.debugLogging)
{
Log.Message($"清理无效子单位: {before} -> {spawned.Count}");
}
}
// 清理验证缓存
if (Find.TickManager.TicksGame - lastValidationCacheClearTick > VALIDATION_CACHE_CLEAR_INTERVAL)
{
validatedChildren.RemoveWhere(c => c == null || c.Destroyed);
lastValidationCacheClearTick = Find.TickManager.TicksGame;
}
}
}
#endregion
public CompProperties_AutoMechCarrier AutoProps => (CompProperties_AutoMechCarrier)props;
// 缓存的合并生产队列
private List<PawnProductionEntry> cachedProductionQueue = null;
private int lastProductionQueueUpdateTick = -1;
private const int PRODUCTION_QUEUE_CACHE_TICKS = 30; // 30 tick缓存
private const int PRODUCTION_QUEUE_CACHE_TICKS = 30;
/// <summary>
/// 获取合并后的生产队列
/// 包括从HediffComp扫描的和动态添加的
/// </summary>
public List<PawnProductionEntry> GetProductionQueue()
{
// 使用缓存提高性能
if (cachedProductionQueue != null &&
Find.TickManager.TicksGame - lastProductionQueueUpdateTick < PRODUCTION_QUEUE_CACHE_TICKS)
{
return cachedProductionQueue;
}
// 获取Pawn引用
try
{
var pawn = parent as Pawn;
// 从AutoProps获取合并后的生产队列
cachedProductionQueue = AutoProps.GetMergedProductionQueue(pawn);
lastProductionQueueUpdateTick = Find.TickManager.TicksGame;
return cachedProductionQueue;
}
catch (System.Exception ex)
{
Log.Error($"获取生产队列失败: {ex.Message}");
return new List<PawnProductionEntry>();
}
}
/// <summary>
/// 强制刷新生产队列缓存
@@ -277,6 +487,23 @@ namespace ArachnaeSwarm
lastProductionQueueUpdateTick = -1;
}
/// <summary>
/// 安全获取已生成的Pawn列表
/// </summary>
private List<Pawn> GetSafeSpawnedPawns()
{
lock (validationLock)
{
var spawned = SpawnedPawns;
if (spawned == null)
return new List<Pawn>();
spawned.RemoveAll(p => p == null || p.Destroyed || (p is Pawn pawn && pawn.Dead));
return spawned;
}
}
/// <summary>
/// 获取总容量
/// </summary>
@@ -284,14 +511,17 @@ namespace ArachnaeSwarm
private int LiveSpawnedPawnsCount(PawnKindDef kind)
{
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
return SpawnedPawns.Count(p => p.kindDef == kind);
var spawned = GetSafeSpawnedPawns();
return spawned.Count(p => p.kindDef == kind);
}
private AcceptanceReport CanSpawnNow(PawnKindDef kind)
{
try
{
if (parent is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Downed || pawn.Dead || !pawn.Spawned))
return false;
if (CooldownTicksRemaining > 0)
return "CooldownTime".Translate() + " " + CooldownTicksRemaining.ToStringSecondsFromTicks();
@@ -304,10 +534,19 @@ namespace ArachnaeSwarm
if (!AutoProps.freeProduction && InnerContainer.TotalStackCountOfDef(Props.fixedIngredient) < cost)
return "MechCarrierNotEnoughResources".Translate();
return true;
}
catch (System.Exception ex)
{
Log.Error($"CanSpawnNow检查失败: {ex.Message}");
return $"生产检查失败: {ex.Message}";
}
}
private void TrySpawnPawn(PawnKindDef kind)
{
try
{
PawnGenerationRequest request = new PawnGenerationRequest(kind, parent.Faction, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: true);
Pawn pawn = PawnGenerator.GeneratePawn(request);
@@ -316,7 +555,6 @@ namespace ArachnaeSwarm
var producedComp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (producedComp == null)
{
// 如果pawn没有这个Comp添加它
var compProps = new CompProperties_ProducedByMechCarrier();
compProps.compClass = typeof(CompProducedByMechCarrier);
var newComp = (CompProducedByMechCarrier)Activator.CreateInstance(compProps.compClass);
@@ -326,10 +564,15 @@ namespace ArachnaeSwarm
producedComp = newComp;
}
// 初始化生产者信息
producedComp.Initialize(parent, this);
// 初始化生产者信息 - 使用安全初始化
bool initSuccess = producedComp.InitializeSafe(parent, this);
if (!initSuccess)
{
Log.Error($"初始化CompProducedByMechCarrier失败");
return;
}
// 生成位置:使用自定义跟随位置(如果有效),否则使用父单位位置
// 生成位置
IntVec3 spawnPosition;
Map spawnMap;
@@ -344,8 +587,20 @@ namespace ArachnaeSwarm
spawnMap = parent.Map;
}
// 验证生成位置
if (!spawnPosition.IsValid || !spawnPosition.InBounds(spawnMap))
{
spawnPosition = parent.Position;
spawnMap = parent.Map;
}
GenSpawn.Spawn(pawn, spawnPosition, spawnMap);
SpawnedPawns.Add(pawn);
// 添加到已生成列表
lock (validationLock)
{
SpawnedPawns?.Add(pawn);
}
if (parent is Pawn p && p.GetLord() != null)
p.GetLord().AddPawn(pawn);
@@ -373,38 +628,61 @@ namespace ArachnaeSwarm
EffecterTrigger(Props.spawnedMechEffecter, Props.attachSpawnedMechEffecter, pawn);
if (Props.spawnEffecter != null)
EffecterTrigger(Props.spawnEffecter, Props.attachSpawnedEffecter, parent);
if (AutoProps.debugLogging)
Log.Message($"成功生成子单位: {pawn.LabelCap}");
}
catch (System.Exception ex)
{
Log.Error($"生成Pawn失败: {ex.Message}");
}
}
private void EffecterTrigger(EffecterDef effecterDef, bool attach, Thing target)
{
try
{
Effecter effecter = new Effecter(effecterDef);
effecter.Trigger(attach ? ((TargetInfo)target) : new TargetInfo(target.Position, target.Map), TargetInfo.Invalid);
effecter.Cleanup();
}
catch (System.Exception ex)
{
Log.Error($"触发效果失败: {ex.Message}");
}
}
public override void CompTick()
{
try
{
base.CompTick();
// 清理无效的子单位引用
if (Find.TickManager.TicksGame - lastChildCleanupTick > CHILD_CLEANUP_INTERVAL)
{
CleanupInvalidChildren();
lastChildCleanupTick = Find.TickManager.TicksGame;
}
// 检查临时位置是否过期
CheckTemporaryPositionExpiry();
if (parent.IsHashIntervalTick(60)) // 每秒检查一次
if (parent.IsHashIntervalTick(60))
{
// 检查是否有抑制生产的Hediff
if (AutoProps.disableHediff != null && (parent as Pawn)?.health.hediffSet.HasHediff(AutoProps.disableHediff) == true)
{
return; // 有Hediff停止生产
return;
}
// 获取当前生产队列
var productionQueue = GetProductionQueue();
if (productionQueue == null || productionQueue.Count == 0)
{
return; // 生产队列为空,不进行生产
return;
}
// 1. 先检查是否满员
// 检查是否满员
bool isFull = true;
foreach (var entry in productionQueue)
{
@@ -417,13 +695,11 @@ namespace ArachnaeSwarm
if (isFull)
{
return; // 如果已满员,则不进行任何操作,包括冷却计时
return;
}
// 2. 如果未满员,才检查冷却时间
if (CooldownTicksRemaining > 0) return;
// 3. 寻找空位并生产
foreach (var entry in productionQueue)
{
if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
@@ -431,12 +707,17 @@ namespace ArachnaeSwarm
if (CanSpawnNow(entry.pawnKind).Accepted)
{
TrySpawnPawn(entry.pawnKind);
break; // 每次只生产一个
break;
}
}
}
}
}
catch (System.Exception ex)
{
Log.Error($"CompAutoMechCarrier Tick错误: {ex.Message}");
}
}
/// <summary>
/// 添加动态生产队列条目
@@ -523,21 +804,21 @@ namespace ArachnaeSwarm
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
// 移除所有Gizmo逻辑
return Enumerable.Empty<Gizmo>();
}
public override string CompInspectStringExtra()
{
SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
string text = "Pawns: " + SpawnedPawns.Count + " / " + TotalPawnCapacity;
try
{
var spawned = GetSafeSpawnedPawns();
string text = "Pawns: " + spawned.Count + " / " + TotalPawnCapacity;
var productionQueue = GetProductionQueue();
foreach (var entry in productionQueue)
{
text += $"\n- {entry.pawnKind.LabelCap}: {LiveSpawnedPawnsCount(entry.pawnKind)} / {entry.count}";
// 显示自定义信息
if (entry.customInfo != null)
{
text += $" ({entry.customInfo})";
@@ -554,7 +835,6 @@ namespace ArachnaeSwarm
text += "\n" + base.CompInspectStringExtra();
}
// 显示自定义跟随位置信息
if (HasValidCustomFollowPosition)
{
text += $"\nCustom Follow Position: {customFollowPosition.Value}";
@@ -568,44 +848,59 @@ namespace ArachnaeSwarm
}
}
// 显示验证状态
if (AutoProps.debugLogging)
{
text += $"\n验证缓存: {validatedChildren.Count}";
text += $"\n死亡队列: {childDeathQueue.Count}";
}
return text;
}
catch (System.Exception ex)
{
return $"状态获取错误: {ex.Message}";
}
}
/// <summary>
/// 获取调试信息
/// </summary>
public string GetDebugInfo()
{
var pawn = parent as Pawn;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("=== CompAutoMechCarrier 调试信息 ===");
// CompAutoMechCarrier基本信息
sb.AppendLine($"父单位: {parent?.LabelCap ?? "NULL"}");
sb.AppendLine($"自定义跟随位置: {CustomFollowPosition}");
sb.AppendLine($"有效跟随位置: {GetEffectiveFollowPosition()}");
sb.AppendLine($"临时位置过期tick: {temporaryPositionExpiryTick}");
// 生产者信息
sb.AppendLine($"生产者有效: {IsProducerValid}");
sb.AppendLine($"生产者存活: {IsProducerAlive}");
// 已生成的Pawn
sb.AppendLine($"已生成Pawn数: {SpawnedPawns?.Count ?? 0}");
if (SpawnedPawns != null && SpawnedPawns.Count > 0)
{
foreach (var spawnedPawn in SpawnedPawns)
var spawned = GetSafeSpawnedPawns();
sb.AppendLine($"已生成Pawn数: {spawned.Count}");
foreach (var spawnedPawn in spawned)
{
if (spawnedPawn != null && !spawnedPawn.Destroyed)
{
sb.AppendLine($" • {spawnedPawn.LabelCap} ({spawnedPawn.kindDef?.label ?? ""})");
}
// 检查双向验证
var childComp = spawnedPawn.TryGetComp<CompProducedByMechCarrier>();
bool valid = childComp != null && childComp.IsProducerValid;
sb.AppendLine($" 双向验证: {valid}");
}
}
// 冷却时间
sb.AppendLine($"冷却时间剩余: {CooldownTicksRemaining}");
// 验证缓存
sb.AppendLine($"验证缓存数: {validatedChildren.Count}");
sb.AppendLine($"死亡队列: {childDeathQueue.Count}");
return sb.ToString();
}
public override void PostExposeData()
{
try
{
base.PostExposeData();
@@ -613,12 +908,20 @@ namespace ArachnaeSwarm
Scribe_Values.Look(ref customFollowPosition, "customFollowPosition");
Scribe_Values.Look(ref temporaryPositionExpiryTick, "temporaryPositionExpiryTick", -1);
// 注意Map不能直接序列化需要在PostLoadInit中重新获取
// 保存验证缓存
Scribe_Collections.Look(ref validatedChildren, "validatedChildren", LookMode.Reference);
Scribe_Collections.Look(ref childDeathQueue, "childDeathQueue", LookMode.Reference);
if (Scribe.mode == LoadSaveMode.LoadingVars)
{
customFollowPositionMap = parent?.Map;
}
}
catch (System.Exception ex)
{
Log.Error($"CompAutoMechCarrier 序列化错误: {ex.Message}");
}
}
public override void PostSpawnSetup(bool respawningAfterLoad)
{
@@ -629,7 +932,6 @@ namespace ArachnaeSwarm
{
customFollowPositionMap = parent?.Map;
// 如果自定义位置无效,清除它
if (customFollowPosition.HasValue &&
(customFollowPositionMap == null ||
!customFollowPosition.Value.InBounds(customFollowPositionMap)))
@@ -640,6 +942,45 @@ namespace ArachnaeSwarm
// 初始化生产队列缓存
RefreshProductionQueue();
// 初始化验证系统
lock (validationLock)
{
if (validatedChildren == null)
validatedChildren = new HashSet<Thing>();
if (childDeathQueue == null)
childDeathQueue = new Queue<Thing>();
}
}
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
try
{
// 清理所有子单位引用
lock (validationLock)
{
var spawned = GetSafeSpawnedPawns();
foreach (var pawn in spawned)
{
var comp = pawn.TryGetComp<CompProducedByMechCarrier>();
if (comp != null)
{
comp.TryUpdateProducerStatus();
}
}
validatedChildren.Clear();
childDeathQueue.Clear();
}
}
catch (System.Exception ex)
{
Log.Error($"销毁时清理失败: {ex.Message}");
}
base.PostDestroy(mode, previousMap);
}
}
}

View File

@@ -6,15 +6,39 @@ using Verse.AI;
namespace ArachnaeSwarm
{
public class CompProducedByMechCarrier : ThingComp
public class CompProducedByMechCarrier : ThingComp, IBidirectionalValidator
{
private Thing producer;
private CompAutoMechCarrier producerComp;
private int lastProducerCheckTick = -1;
private const int PRODUCER_CHECK_INTERVAL = 60;
public Thing Producer => producer;
public CompAutoMechCarrier ProducerComp => producerComp;
// 死亡检测相关
private bool wasDead = false;
private int deathTick = -1;
private const int DEATH_CLEANUP_DELAY = 60; // 死后60tick进行清理
// 安全锁
private object validationLock = new object();
// === IBidirectionalValidator 实现 ===
public bool IsProducerValid
{
get
{
lock (validationLock)
{
if (producer == null || producer.Destroyed)
return false;
// 如果是pawn检查是否死亡或倒下
if (producer is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
}
}
// 公开属性,用于其他类访问
public bool HasValidProducer
@@ -32,12 +56,121 @@ namespace ArachnaeSwarm
}
}
public Thing GetProducer()
{
lock (validationLock)
{
return IsProducerValid ? producer : null;
}
}
public bool IsProducerAlive
{
get
{
lock (validationLock)
{
return IsProducerValid && producer.Spawned;
}
}
}
public bool IsChildValid(Thing child)
{
if (child == null || child.Destroyed)
return false;
// 检查是否为pawn
if (!(child is Pawn))
return false;
// 检查是否死亡
if (child is Pawn pawn && (pawn.Dead || pawn.Downed))
return false;
return true;
}
public bool IsChildAlive(Thing child)
{
return IsChildValid(child) && child.Spawned;
}
public bool ValidateBidirectional(Thing child)
{
lock (validationLock)
{
// 验证子单位
if (!IsChildValid(child))
return false;
// 验证生产者
if (!IsProducerValid)
return false;
// 验证双向引用
return ValidateBidirectionalReference(child);
}
}
public bool ValidateAndExecute(Thing child, System.Action action)
{
if (!ValidateBidirectional(child))
return false;
try
{
action?.Invoke();
return true;
}
catch (System.Exception ex)
{
Log.Error($"双向验证执行失败: {ex.Message}");
return false;
}
}
private bool ValidateBidirectionalReference(Thing child)
{
// 检查生产者是否包含这个子单位
var producerCarrier = GetProducerComp();
if (producerCarrier == null)
return false;
// 验证生产者是否知道这个子单位
return producerCarrier.ValidateChildReference(child);
}
// === 接口实现结束 ===
public Thing Producer => GetProducer();
public CompAutoMechCarrier ProducerComp => GetProducerComp();
// 获取生产者组件的安全方法
private CompAutoMechCarrier GetProducerComp()
{
lock (validationLock)
{
if (!IsProducerValid)
return null;
// 如果组件为空,尝试获取
if (producerComp == null || producerComp.parent != producer)
{
producerComp = producer.TryGetComp<CompAutoMechCarrier>();
}
return producerComp;
}
}
// 检查是否应该跟随生产者
public bool ShouldFollowProducer
{
get
{
if (!HasValidProducer)
lock (validationLock)
{
if (!IsProducerValid)
return false;
// 确保pawn是有效的
@@ -49,16 +182,39 @@ namespace ArachnaeSwarm
if (producer.Map != pawn.Map || !pawn.CanReach(producer, PathEndMode.OnCell, Danger.Deadly))
return false;
// 可以根据需要添加更多条件
return true;
}
}
}
// 初始化方法 - 安全版本
public bool InitializeSafe(Thing producer, CompAutoMechCarrier producerComp)
{
lock (validationLock)
{
// 验证生产者
if (producer == null || producer.Destroyed)
return false;
// 验证生产者组件
if (producerComp == null || producerComp.parent != producer)
return false;
this.producer = producer;
this.producerComp = producerComp;
// 记录初始化时间
lastProducerCheckTick = Find.TickManager.TicksGame;
Log.Message($"双向验证: {parent?.LabelCap} -> {producer.LabelCap} 初始化成功");
return true;
}
}
// 初始化方法
// 原始初始化方法(保持向后兼容)
public void Initialize(Thing producer, CompAutoMechCarrier producerComp)
{
this.producer = producer;
this.producerComp = producerComp;
InitializeSafe(producer, producerComp);
}
// 尝试更新生产者状态
@@ -69,9 +225,61 @@ namespace ArachnaeSwarm
lastProducerCheckTick = Find.TickManager.TicksGame;
lock (validationLock)
{
// 检查生产者是否仍然有效
if (producer != null && (producer.Destroyed || (producer is Pawn p && (p.Dead || p.Downed))))
{
Log.Warning($"生产者无效: {producer?.LabelCap}, 清除引用");
producer = null;
producerComp = null;
}
// 检查自身状态
CheckSelfStatus();
}
}
// 检查自身状态
private void CheckSelfStatus()
{
// 检查是否死亡
if (parent is Pawn pawn)
{
if (pawn.Dead)
{
if (!wasDead)
{
wasDead = true;
deathTick = Find.TickManager.TicksGame;
Log.Message($"子单位死亡: {pawn.LabelCap}, 准备通知生产者");
}
// 死亡后延迟清理
if (deathTick >= 0 && Find.TickManager.TicksGame - deathTick >= DEATH_CLEANUP_DELAY)
{
NotifyProducerOfDeath();
}
}
else
{
wasDead = false;
deathTick = -1;
}
}
}
// 通知生产者自己死亡
private void NotifyProducerOfDeath()
{
lock (validationLock)
{
if (producerComp != null && !producerComp.parent.Destroyed)
{
producerComp.NotifyChildDeath(parent);
}
// 清除引用
producer = null;
producerComp = null;
}
@@ -80,16 +288,21 @@ namespace ArachnaeSwarm
// 获取生产者的位置
public IntVec3 GetProducerPosition()
{
if (!HasValidProducer)
lock (validationLock)
{
if (!IsProducerValid)
return IntVec3.Invalid;
return producer.Position;
}
}
// 获取生产者的交互单元格
public IntVec3 GetProducerInteractionCell()
{
if (!HasValidProducer)
lock (validationLock)
{
if (!IsProducerValid)
return IntVec3.Invalid;
if (producer is Building building)
@@ -97,21 +310,90 @@ namespace ArachnaeSwarm
return producer.Position;
}
}
// 检查是否在生产者附近
public bool IsNearProducer(Pawn pawn, float radius)
{
if (!HasValidProducer)
lock (validationLock)
{
if (!IsProducerValid)
return false;
return pawn.Position.DistanceTo(producer.Position) <= radius;
}
}
// === Tick 方法 ===
public override void CompTick()
{
base.CompTick();
try
{
// 定期检查生产者状态
TryUpdateProducerStatus();
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier Tick错误: {ex.Message}");
}
}
public override void CompTickRare()
{
base.CompTickRare();
try
{
// 定期清理
lock (validationLock)
{
if (producer != null && producer.Destroyed)
{
producer = null;
producerComp = null;
}
}
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier TickRare错误: {ex.Message}");
}
}
public override void PostExposeData()
{
base.PostExposeData();
try
{
Scribe_References.Look(ref producer, "producer");
Scribe_Values.Look(ref lastProducerCheckTick, "lastProducerCheckTick", -1);
Scribe_Values.Look(ref wasDead, "wasDead", false);
Scribe_Values.Look(ref deathTick, "deathTick", -1);
}
catch (System.Exception ex)
{
Log.Error($"CompProducedByMechCarrier 序列化错误: {ex.Message}");
}
}
// === 调试方法 ===
public string GetValidationStatus()
{
lock (validationLock)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine($"=== {parent?.LabelCap} 验证状态 ===");
sb.AppendLine($"生产者有效: {IsProducerValid}");
sb.AppendLine($"生产者存活: {IsProducerAlive}");
sb.AppendLine($"生产者: {producer?.LabelCap ?? "NULL"}");
sb.AppendLine($"生产者组件: {producerComp != null}");
sb.AppendLine($"上次检查: {lastProducerCheckTick}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,26 @@
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 双向安全校验接口
/// 确保生产者和子单位在操作前互相验证存在
/// </summary>
public interface IBidirectionalValidator
{
// 生产者相关
bool IsProducerValid { get; }
Thing GetProducer();
bool IsProducerAlive { get; }
// 子单位相关
bool IsChildValid(Thing child);
bool IsChildAlive(Thing child);
// 双向验证
bool ValidateBidirectional(Thing child);
bool ValidateAndExecute(Thing child, System.Action action);
}
}