This commit is contained in:
Tourswen
2025-12-16 23:54:36 +08:00
parent 18fd9ec2d9
commit 3706bdb241
37 changed files with 3212 additions and 407 deletions

Binary file not shown.

View File

@@ -271,57 +271,6 @@
</ThingDef>
<!-- 战士 -->
<AbilityDef>
<defName>ARA_BaseRace_Acid_Launcher</defName>
<label>酸噬种投射</label>
<description>将一只阿拉克涅酸噬种辅虫发射到指定地点,落地后这只寿命有限的辅虫将立刻对敌人展开攻击。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_BaseRace_Launcher</iconPath>
<cooldownTicksRange>5000</cooldownTicksRange>
<aiCanUse>true</aiCanUse>
<displayOrder>300</displayOrder>
<displayGizmoWhileUndrafted>false</displayGizmoWhileUndrafted>
<warmupStartSound>AcidSpray_Warmup</warmupStartSound>
<charges>3</charges>
<cooldownPerCharge>true</cooldownPerCharge>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<range>24</range>
<warmupTime>1</warmupTime>
<soundCast>AcidSpray_Resolve</soundCast>
<violent>false</violent>
<targetParams>
<canTargetLocations>true</canTargetLocations>
</targetParams>
</verbProperties>
<comps>
<li Class="CompProperties_AbilityLaunchProjectile">
<projectileDef>ArachnaeBase_Race_Acidcut_Proj</projectileDef>
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
<customLabel>饮食</customLabel>
<showProgressBar>true</showProgressBar>
<needDef>Food</needDef>
<needCost>0.2</needCost>
<failMessage>营养值不足,需要进食</failMessage>
</li>
</comps>
</AbilityDef>
<ThingDef ParentName="BaseGrenadeProjectile">
<defName>ArachnaeBase_Race_Acidcut_Proj</defName>
<label>阿拉克涅酸噬种</label>
<thingClass>Projectile_SpawnsPawnZeroAge</thingClass>
<graphicData>
<texPath>ArachnaeSwarm/Things/ARA_Acidcut/Bodies/Naked_Thin</texPath>
<graphicClass>Graphic_Multi</graphicClass>
</graphicData>
<projectile>
<speed>41</speed>
<spawnsPawnKind>ArachnaeBase_Race_Acidcut</spawnsPawnKind>
<tryAdjacentFreeSpaces>true</tryAdjacentFreeSpaces>
<damageDef>ARA_AcidBurn</damageDef>
<damageAmountBase>10</damageAmountBase>
</projectile>
</ThingDef>
<AbilityDef>
<defName>ARA_Toxic_Needle_Fire</defName>
<label>毒针连射</label>

View File

@@ -381,6 +381,11 @@
</li>
</stages> -->
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Fighter_Base_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
<li Class="HediffCompProperties_GiveAbility">
<abilityDefs>
<li>ARA_AcidSprayBurst</li>
@@ -830,7 +835,7 @@
<HediffDef>
<defName>ARA_ShieldHead_Base</defName>
<label>坚硬甲壳</label>
<description>盾头种虽然身材较小而没有大型阿拉克涅虫族那样的压迫感,但是得益于其覆盖全身的甲壳,防御力可一点不比那些大型虫族弱。它的甲壳被特意设置为会过度生长并脱落虫族则可以利用其脱落的甲壳作为建设巢穴的工具。一只盾头种每天产出15份甲壳素。</description>
<description>盾头种虽然身材较小而没有大型阿拉克涅虫族那样的压迫感,但是得益于其覆盖全身的甲壳,防御力可一点不比那些大型虫族弱。</description>
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad>
@@ -1052,7 +1057,7 @@
<HediffDef>
<defName>ARA_ShieldHead_HiveBuilder</defName>
<label>亚种-营建种</label>
<description>这只阿拉克涅盾头种已经获得拔耀,获得了强大的产出能力和建造能力。一只盾头种每天产出25份甲壳素。</description>
<description>这只阿拉克涅盾头种已经获得拔耀,获得了强大的产出能力和建造能力。一只盾头种每天额外产出15份甲壳素。</description>
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad>
@@ -1075,7 +1080,7 @@
<!-- 要生成的物品的ThingDef。 -->
<thingToSpawn>ARA_Carapace</thingToSpawn>
<!-- 每次生成的基础物品数量。 -->
<spawnCount>25</spawnCount>
<spawnCount>15</spawnCount>
<!--
==================================================
生成周期 (Spawning Interval)
@@ -1429,6 +1434,11 @@
</li>
</stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Praetorian_Base_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
<li Class="HediffCompProperties_GiveAbility">
<abilityDefs>
<li>ARA_Praetorian_jump</li>

View File

@@ -13,7 +13,7 @@
<suspendable>false</suspendable>
</JobDef>
<JobDef>
<JobDef>
<defName>ARA_EnterPowerArmor</defName>
<driverClass>ArachnaeSwarm.JobDriver_EnterPowerArmor</driverClass>
<reportString>entering TargetA.</reportString>

View File

@@ -290,9 +290,6 @@
</categories>
</li>
</backstoryFiltersOverride>
<abilities>
<li>ARA_BaseRace_Acid_Launcher</li>
</abilities>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
@@ -454,7 +451,7 @@
<lifeStages>
<li>
<bodyGraphicData>
<texPath>ArachnaeSwarm/Things/ARA_Scavenger/Scavenger/Naked_Thin</texPath>
<texPath>ArachnaeSwarm/Things/ARA_Scavenger/Maid/Naked_Thin</texPath>
<drawSize>1</drawSize>
<color>(156,148,125)</color>
<shadowData>

View File

@@ -8,15 +8,15 @@
<ResearchProjectDef Abstract="True" Name="ARA_techBase_Needtechprint" ParentName="ARA_techBase">
<techLevel>Medieval</techLevel>
<tab>ARA_ResearchTab</tab>
<techprintCount>1</techprintCount>
<!-- <techprintCount>1</techprintCount>
<techprintCommonality>0</techprintCommonality>
<techprintMarketValue>2500</techprintMarketValue>
<techprintMarketValue>2500</techprintMarketValue> -->
<hiddenPrerequisites>
<li>ARA_Technology_5ESS</li>
</hiddenPrerequisites>
<heldByFactionCategoryTags>
<!-- <heldByFactionCategoryTags>
<li>ARA_New_Hive</li>
</heldByFactionCategoryTags>
</heldByFactionCategoryTags> -->
</ResearchProjectDef>
<!-- 女皇工艺进化 -->

View File

@@ -1681,7 +1681,6 @@
<soundInteract>SpitterSpawn</soundInteract>
<recipeMaker>
<recipeUsers Inherit="False" />
<researchPrerequisite>ARA_Technology_5PAV</researchPrerequisite>
<unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef>
</recipeMaker>
<statBases>
@@ -1974,6 +1973,88 @@
<speed>40</speed>
</projectile>
</ThingDef>
<ThingDef ParentName="BaseWeaponTurret">
<defName>ARA_Fighter_Base_Turret</defName>
<label>酸噬蜂巢</label>
<description>阿拉克涅战士种身上的共生器官,会对敌方附近自动投射酸噬种辅虫。</description>
<graphicData>
<texPath>ArachnaeSwarm/Weapon/ARA_Weapon_Empty</texPath>
<graphicClass>Graphic_Single</graphicClass>
</graphicData>
<descriptionHyperlinks>
<HediffDef>ARA_Skyraider_Hivelord</HediffDef>
</descriptionHyperlinks>
<statBases>
<AccuracyTouch>1</AccuracyTouch>
<AccuracyShort>1</AccuracyShort>
<AccuracyMedium>1</AccuracyMedium>
<AccuracyLong>1</AccuracyLong>
<Mass>0</Mass>
</statBases>
<verbs>
<li>
<verbClass>ArachnaeSwarm.Verb_ShootSelfUnderfoot</verbClass>
<hasStandardCommand>true</hasStandardCommand>
<defaultProjectile>ArachnaeBase_Race_Acidcut_Proj</defaultProjectile>
<range>18</range>
<burstShotCount>1</burstShotCount>
<ticksBetweenBurstShots>2</ticksBetweenBurstShots>
<soundCast>SpitterSpit</soundCast>
<soundCastTail>GunTail_Medium</soundCastTail>
<muzzleFlashScale>9</muzzleFlashScale>
<defaultCooldownTime>12</defaultCooldownTime>
</li>
</verbs>
</ThingDef>
<ThingDef ParentName="BaseWeaponTurret">
<defName>ARA_Praetorian_Base_Turret</defName>
<label>酸噬蜂巢</label>
<description>阿拉克涅禁卫种身上的共生器官,会对敌方附近自动投射酸噬种辅虫。</description>
<graphicData>
<texPath>ArachnaeSwarm/Weapon/ARA_Weapon_Empty</texPath>
<graphicClass>Graphic_Single</graphicClass>
</graphicData>
<descriptionHyperlinks>
<HediffDef>ARA_Skyraider_Hivelord</HediffDef>
</descriptionHyperlinks>
<statBases>
<AccuracyTouch>1</AccuracyTouch>
<AccuracyShort>1</AccuracyShort>
<AccuracyMedium>1</AccuracyMedium>
<AccuracyLong>1</AccuracyLong>
<Mass>0</Mass>
</statBases>
<verbs>
<li>
<verbClass>ArachnaeSwarm.Verb_ShootSelfUnderfoot</verbClass>
<hasStandardCommand>true</hasStandardCommand>
<defaultProjectile>ArachnaeBase_Race_Acidcut_Proj</defaultProjectile>
<range>65</range>
<burstShotCount>1</burstShotCount>
<ticksBetweenBurstShots>2</ticksBetweenBurstShots>
<soundCast>SpitterSpit</soundCast>
<soundCastTail>GunTail_Medium</soundCastTail>
<muzzleFlashScale>9</muzzleFlashScale>
<defaultCooldownTime>2</defaultCooldownTime>
</li>
</verbs>
</ThingDef>
<ThingDef ParentName="BaseGrenadeProjectile">
<defName>ArachnaeBase_Race_Acidcut_Proj</defName>
<label>阿拉克涅酸噬种</label>
<thingClass>Projectile_SpawnsPawnZeroAge</thingClass>
<graphicData>
<texPath>ArachnaeSwarm/Things/ARA_Acidcut/Bodies/Naked_Thin</texPath>
<graphicClass>Graphic_Multi</graphicClass>
</graphicData>
<projectile>
<speed>41</speed>
<spawnsPawnKind>ArachnaeBase_Race_Acidcut</spawnsPawnKind>
<tryAdjacentFreeSpaces>true</tryAdjacentFreeSpaces>
<damageDef>ARA_AcidBurn</damageDef>
<damageAmountBase>10</damageAmountBase>
</projectile>
</ThingDef>
<ThingDef ParentName="BaseWeaponTurret">
<defName>ARA_Skyraider_Hivelord_Turret</defName>
<label>食肉蜂巢</label>

View File

@@ -10,6 +10,7 @@
<pollutionShaderType MayRequire="Ludeon.RimWorld.Biotech">TerrainFadeRoughSoftLight</pollutionShaderType>
<pollutionTintColor>(0.95, 0.95, 0.93, 1)</pollutionTintColor>
<pollutionColor>(240,240,240)</pollutionColor>
<terrainAffordanceNeeded IsNull="True" Inherit="False"/>
<color>(209, 207, 184)</color>
<edgeType>FadeRough</edgeType>
<resourcesFractionWhenDeconstructed>0</resourcesFractionWhenDeconstructed>
@@ -59,6 +60,7 @@
<texturePath>ArachnaeSwarm/Terrain/Surfaces/ARA_InsectCreepTile</texturePath>
<pollutionOverlayTexturePath>Terrain/Surfaces/AncientMegastructure</pollutionOverlayTexturePath>
<pollutionShaderType MayRequire="Ludeon.RimWorld.Biotech">TerrainFadeRoughSoftLight</pollutionShaderType>
<terrainAffordanceNeeded IsNull="True" Inherit="False"/>
<pollutionTintColor>(0.95, 0.95, 0.93, 1)</pollutionTintColor>
<pollutionColor>(240,240,240)</pollutionColor>
<color>(209, 207, 184)</color>
@@ -163,29 +165,64 @@
</li>
</damageMultipliers>
</ThingDef>
<ThingDef ParentName="GraniteBase">
<ThingDef ParentName="Wall">
<defName>ARA_SmoothedInsectWall</defName>
<label>光滑的阿拉克涅甲壳墙</label>
<description>阿拉克涅工蜂将硬质材料和甲壳素混合堆起来形成的墙壁,虫族对这片墙壁进行了精心打磨,质地坚硬的同时看起来美观多了。</description>
<uiIconPath>Things/Building/Linked/WallSmooth_MenuIcon</uiIconPath>
<graphicData>
<texPath>Things/Building/Linked/RockSmooth_Atlas</texPath>
<graphicClass>Graphic_Single</graphicClass>
<shaderType>CutoutComplex</shaderType>
<color>(209, 207, 184)</color>
<shadowData>
<volume>(0.7, 0.4, 0.2)</volume>
<offset>(0,0,-0.1)</offset>
</shadowData>
</graphicData>
<!-- <mineable>true</mineable> -->
<blockLight>true</blockLight>
<staticSunShadowHeight>0</staticSunShadowHeight>
<statBases>
<MarketValue>7</MarketValue>
<MarketValue>5</MarketValue>
<Beauty>1</Beauty>
<MaxHitPoints>1000</MaxHitPoints>
<WorkToBuild>1500</WorkToBuild>
<Flammability>0</Flammability>
<Cleanliness>0</Cleanliness>
</statBases>
<building>
<isNaturalRock>false</isNaturalRock>
<isAirtight>true</isAirtight>
<smoothedThing />
<blueprintGraphicData>
<texPath>ArachnaeSwarm/Building/Linked/ARA_InsectWall_Blueprint</texPath>
</blueprintGraphicData>
<canBuildNonEdificesUnder>true</canBuildNonEdificesUnder>
<artificialForMeditationPurposes>false</artificialForMeditationPurposes>
<smoothedThing />
<paintable>true</paintable>
<relatedBuildCommands>
<li>ARA_InsectDoor</li>
</relatedBuildCommands>
</building>
<saveCompressible>false</saveCompressible>
<repairEffect>Repair</repairEffect>
<useStuffTerrainAffordance>false</useStuffTerrainAffordance>
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
<repairEffect>EatVegetarian</repairEffect>
<costStuffCount>2</costStuffCount>
<stuffCategories Inherit="False">
<li>Metallic</li>
</stuffCategories>
<costList>
<ARA_Carapace>1</ARA_Carapace>
</costList>
<damageMultipliers Inherit="False">
<li>
<damageDef>Bomb</damageDef>
<multiplier>0.1</multiplier>
</li>
<li>
<damageDef>Thump</damageDef>
<multiplier>0.1</multiplier>
</li>
</damageMultipliers>
</ThingDef>
<ThingDef ParentName="DoorBase">
<defName>ARA_InsectDoor</defName>
@@ -329,7 +366,7 @@
<MaxHitPoints>1200</MaxHitPoints>
<Flammability>0</Flammability>
<WorkToBuild>1000</WorkToBuild>
<Beauty>0</Beauty>
<Beauty>1</Beauty>
<DoorOpenSpeed>2</DoorOpenSpeed>
</statBases>
<costStuffCount>10</costStuffCount>
@@ -353,7 +390,6 @@
<useStuffTerrainAffordance>false</useStuffTerrainAffordance>
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
<!-- <terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded> -->
<designationCategory>ARA_Buildings</designationCategory>
<holdsRoof>true</holdsRoof>
<staticSunShadowHeight>0</staticSunShadowHeight>
<blockLight>true</blockLight>
@@ -588,7 +624,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -658,7 +694,7 @@
<comps Inherit="False">
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -734,7 +770,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -805,7 +841,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -880,7 +916,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -961,7 +997,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -1127,7 +1163,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -1183,7 +1219,7 @@
<comps Inherit="False">
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>

View File

@@ -48,7 +48,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>

View File

@@ -38,7 +38,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -173,7 +173,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -410,7 +410,7 @@
<ThingDef ParentName="BuildingBase">
<defName>ARA_JellyVat</defName> <!-- defName is changed to reflect its purpose -->
<label>生物质酿造池</label>
<description>一个阿拉克涅虫族活体组织,可以充分利用活体钜菌的溶解能力,通过消化生物质,来分泌出营养丰富的阿拉克涅虫蜜。</description>
<description>一个阿拉克涅虫族活体组织,可以充分利用活体钜菌的溶解能力,通过消化生物质,来分泌出营养丰富的阿拉克涅虫蜜。阿拉克涅虫蜜会在房间内蔓延,形成蜜池,而生物质酿造池会定期标记这些流淌的蜜浆,命令其他虫族来收集它们。</description>
<thingClass>Building</thingClass>
<graphicData>
<texPath>ArachnaeSwarm/Building/ARA_JellyVat</texPath>
@@ -464,20 +464,53 @@
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
<comps>
<li Class="CompProperties_Flickable"/>
<!--<li Class="ArachnaeSwarm.CompProperties_MultiFuelSpawner">
<spawnIntervalRange>
<min>120000</min>
<max>120000</max>
</spawnIntervalRange>
<products>
<li>
<thingDef>ARA_InsectJelly</thingDef>
<count>60</count>
</li>
</products>
<showMessageIfOwned>true</showMessageIfOwned>
</li>-->
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
<allowedRaces>
<li>ArachnaeNode_Race_WeaponSmith</li>
</allowedRaces>
</li>
<!-- 地形改变组件 -->
<li Class="ArachnaeSwarm.CompProperties_TerrainChanger">
<targetTerrain>ARA_InsectJelly_Terrain</targetTerrain>
<baseChangeInterval>600</baseChangeInterval> <!-- 2天 -->
<requiresFuel>true</requiresFuel>
<fuelConsumptionPerChange>1</fuelConsumptionPerChange>
<minFuelToOperate>1</minFuelToOperate>
<changeRadius>10</changeRadius>
<onlyInSameRoom>true</onlyInSameRoom>
<prioritizeClosest>true</prioritizeClosest>
<requiresPower>false</requiresPower>
<poweredWorkSpeedMultiplier>1</poweredWorkSpeedMultiplier>
<!-- 自动标记拆除功能 -->
<enableAutoMarkForRemoval>true</enableAutoMarkForRemoval>
<markRemovalInterval>600</markRemovalInterval> <!-- 4天 -->
<markRemovalRadius>10</markRemovalRadius>
<fuelConsumptionPerMark>0</fuelConsumptionPerMark>
<!-- 只将这些地形转换为营养液 -->
<!-- <acceptedTerrains>
<li>TileSandstone</li>
<li>TileGranite</li>
<li>TileLimestone</li>
<li>TileMarble</li>
<li>TileSlate</li>
</acceptedTerrains> -->
<!-- 视觉效果 -->
<showVisualEffects>true</showVisualEffects>
<!-- <workingEffecter>Spraying_Nutrient</workingEffecter> -->
<workingSound>AcidSpray_Resolve</workingSound>
<completionSound>AcidSpray_Resolve</completionSound>
</li>
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
<saveKeysPrefix>Biomass</saveKeysPrefix>
<fuelLabel>生物质</fuelLabel>
@@ -499,50 +532,42 @@
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
<showAllowAutoRefuelToggle>false</showAllowAutoRefuelToggle>
</li>
<li Class="ArachnaeSwarm.CompProperties_NutritionToFuelConverter">
<checkInterval>200</checkInterval>
<nutritionCost>0.25</nutritionCost>
<workAmount>2000</workAmount>
<fuelAmount>1</fuelAmount>
</li>
<li Class="ArachnaeSwarm.CompProperties_ProductStorage">
<fuelLabel>虫蜜</fuelLabel>
<fuelGizmoLabel>虫蜜</fuelGizmoLabel>
<fuelCapacity>25</fuelCapacity>
<fuelConsumptionRate>0</fuelConsumptionRate>
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
<fuelFilter>
<thingDefs>
<li>ARA_InsectJelly</li>
</thingDefs>
</fuelFilter>
<allowRefuelIfNotEmpty>false</allowRefuelIfNotEmpty>
<drawFuelGaugeInMap>false</drawFuelGaugeInMap>
<drawOutOfFuelOverlay>false</drawOutOfFuelOverlay>
<targetFuelLevelConfigurable>false</targetFuelLevelConfigurable>
<showAllowAutoRefuelToggle>false</showAllowAutoRefuelToggle>
<canEjectFuel>true</canEjectFuel>
</li>
<!-- 燃料满了自动弹出 -->
<li Class="ArachnaeSwarm.CompProperties_AutoEjector">
<checkInterval>60</checkInterval>
<ejectAtPercent>0.99</ejectAtPercent>
<allowEjectedFuel>true</allowEjectedFuel>
<monitorProductStorage>true</monitorProductStorage>
<monitorRefuelable>false</monitorRefuelable>
</li>
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
<spawnRadius>6</spawnRadius>
</li>
</comps>
</ThingDef>
<TerrainDef ParentName="FloorBase">
<defName>ARA_InsectJelly_Terrain</defName>
<label>阿拉克涅虫蜜</label>
<renderPrecedence>250</renderPrecedence>
<texturePath>ArachnaeSwarm/Terrain/Surfaces/ARA_InsectJelly_Terrain</texturePath>
<burnedDef>ARA_InsectCreep</burnedDef>
<color>(231, 224, 188)</color>
<pollutionOverlayTexturePath>Terrain/Surfaces/AncientMegastructure</pollutionOverlayTexturePath>
<pollutionShaderType MayRequire="Ludeon.RimWorld.Biotech">TerrainFadeRoughSoftLight</pollutionShaderType>
<statBases>
<WorkToBuild>85</WorkToBuild>
<Flammability>0.22</Flammability>
</statBases>
<costList>
<ARA_InsectJelly>2</ARA_InsectJelly>
</costList>
<avoidWander>true</avoidWander>
<waterBodyType>Freshwater</waterBodyType>
<waterDepthShader>Map/WaterDepth</waterDepthShader>
<pathCost>100</pathCost>
<edgeType>Water</edgeType>
<categoryType>Misc</categoryType>
<renderPrecedence>390</renderPrecedence>
<takeFootprints>false</takeFootprints>
<fertility>1</fertility>
<holdSnowOrSand>false</holdSnowOrSand>
<extraDeteriorationFactor>600</extraDeteriorationFactor> <!-- 25 an hour -->
<!-- <glowRadius>3</glowRadius>
<glowColor>(214,94,4,0)</glowColor> -->
<supportsRock>false</supportsRock>
<filthAcceptanceMask Inherit="False">
<li>None</li>
</filthAcceptanceMask>
</TerrainDef>
<ThingDef ParentName="BuildingBase">
<defName>ARA_Carapace_Productor</defName>
<label>骨花</label>
@@ -601,39 +626,109 @@
<comps>
<li Class="CompProperties_Flickable"/>
<!-- First fuel component: Steel -->
<li Class="ArachnaeSwarm.CompProperties_RefuelableWithKey">
<saveKeysPrefix>Steels</saveKeysPrefix>
<fuelLabel>钢铁</fuelLabel>
<fuelGizmoLabel>钢铁</fuelGizmoLabel>
<fuelFilter>
<thingDefs>
<li>Steel</li>
</thingDefs>
</fuelFilter>
<fuelCapacity>50</fuelCapacity>
<fuelConsumptionRate>50</fuelConsumptionRate>
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
<!-- 尸体转换组件 -->
<li Class="ArachnaeSwarm.CompProperties_CorpseConverter">
<targetThingDef>ARA_Carapace_Column</targetThingDef>
<targetThingCount>1</targetThingCount>
<conversionInterval>1200</conversionInterval> <!-- 2天 -->
<conversionRadius>10</conversionRadius>
<requiresPower>false</requiresPower>
<requiresFuel>false</requiresFuel>
<!-- <fuelConsumptionPerConversion>8</fuelConsumptionPerConversion>
<minFuelToOperate>0.5</minFuelToOperate> -->
<!-- 只接受特定尸体(可选,如果注释掉则接受所有尸体) -->
<!--
<acceptedCorpseDefs>
<li>Corpse_Human</li>
<li>Corpse_Megascarab</li>
<li>Corpse_Spelopede</li>
<li>Corpse_Megaspider</li>
</acceptedCorpseDefs>
-->
<!-- 视觉效果 -->
<showVisualEffects>true</showVisualEffects>
<!-- <workingEffecter>Mote_CorpseConverter_Working</workingEffecter>
<conversionEffecter>Mote_CorpseConverter_Conversion</conversionEffecter> -->
<workingSound>PowerOnSmall</workingSound>
<conversionSound>DropPod_Leaving</conversionSound>
<completionSound>ResearchComplete</completionSound>
<!-- 显示设置 -->
<showProgress>true</showProgress>
<showRadius>true</showRadius>
<!-- 自动标记拆除配置 -->
<enableAutoMarkForDeconstruction>true</enableAutoMarkForDeconstruction>
<markDeconstructionInterval>1200</markDeconstructionInterval> <!-- 3天 -->
<markDeconstructionRadius>10</markDeconstructionRadius>
<fuelConsumptionPerMark>0</fuelConsumptionPerMark>
<!-- <markEffecter>Mote_CorpseConverter_Mark</markEffecter> -->
<!-- <markSound>Hiss</markSound>
<markCompleteSound>ResearchComplete</markCompleteSound> -->
<!-- 排除机械族尸体 -->
<excludeMechanoidCorpses>true</excludeMechanoidCorpses>
</li>
<!-- Our simple spawner component -->
<li Class="ArachnaeSwarm.CompProperties_MultiFuelSpawner">
<spawnIntervalRange>60000~60000</spawnIntervalRange>
<products>
<li>
<thingDef>ARA_Carapace</thingDef>
<count>25</count>
</li>
</products>
<showMessageIfOwned>true</showMessageIfOwned>
</li>
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
<spawnRadius>6</spawnRadius>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
<allowedRaces>
<li>ArachnaeNode_Race_WeaponSmith</li>
</allowedRaces>
</li>
</comps>
</ThingDef>
<ThingDef ParentName="BuildingBase">
<defName>ARA_Carapace_Column</defName>
<label>骨柱</label>
<description>阿拉克涅的骨花通过催化尸体而转变得到的柱子,。</description>
<uiOrder>2040</uiOrder>
<altitudeLayer>Building</altitudeLayer>
<passability>PassThroughOnly</passability>
<fillPercent>0.25</fillPercent>
<pathCost>0</pathCost>
<uiIconScale>0.8</uiIconScale>
<graphicData>
<drawSize>(1.25,1.25)</drawSize>
<drawOffset>(0,0,0.2)</drawOffset>
<texPath>ArachnaeSwarm/Building/ARA_Column</texPath>
<graphicClass>Graphic_Single</graphicClass>
<shaderType>CutoutComplex</shaderType>
<shadowData>
<volume>(0.3, 0.5, 0.3)</volume>
<offset>(0,0,-0.23)</offset>
</shadowData>
<damageData>
<rect>(0.2,0.2,0.6,0.6)</rect>
</damageData>
</graphicData>
<statBases>
<MaxHitPoints>20</MaxHitPoints>
<WorkToBuild>750</WorkToBuild>
<Mass>10</Mass>
<Flammability>0</Flammability>
<Beauty>0</Beauty>
</statBases>
<costStuffCount>0</costStuffCount>
<stuffCategories Inherit="False"/>
<costList>
<ARA_Carapace>20</ARA_Carapace>
</costList>
<holdsRoof>true</holdsRoof>
<canOverlapZones>false</canOverlapZones>
<rotatable>false</rotatable>
<fertility>0</fertility>
<building>
<isInert>true</isInert>
<ai_chillDestination>false</ai_chillDestination>
<paintable>true</paintable>
</building>
</ThingDef>
</Defs>

View File

@@ -56,7 +56,7 @@
</li>
</tools>
<costList>
<ARA_InsectJelly>1</ARA_InsectJelly>
<ARA_InsectJelly>3</ARA_InsectJelly>
</costList>
</TerrainDef>
@@ -145,13 +145,17 @@
<li>ArachnaeSwarm.ITab_Ootheca_Incubation</li>
</inspectorTabs>
<costList>
<ARA_InsectJelly>25</ARA_InsectJelly>
</costList>
<placeWorkers>
<li>ArachnaeSwarm.PlaceWorker_CustomRadius</li>
</placeWorkers>
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -175,7 +179,7 @@
<buttonLabel>孵化···</buttonLabel>
<buttonDesc>选择孵化的阿拉克涅督虫···</buttonDesc>
<menuTitle>孵化菜单</menuTitle>
<defaultIconPath>UI/Commands/IncubatorSwitch</defaultIconPath>
<defaultIconPath>ArachnaeSwarm/UI/Commands/ARA_NodeSwarmIcon</defaultIconPath>
<!-- 全局Hediff奖励所有配置共享 -->
<globalExtraHediffs>
@@ -220,7 +224,6 @@
<li>
<pawnKind>ArachnaeNode_Race_ShieldHead</pawnKind>
<daysRequired>2</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
<li>ARA_Incubator_2_Reward_Hediffs</li>
@@ -235,7 +238,6 @@
<li>
<pawnKind>ArachnaeNode_Race_WeaponSmith</pawnKind>
<daysRequired>2</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
<li>ARA_Incubator_2_Reward_Hediffs</li>
@@ -250,7 +252,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Fighter</pawnKind>
<daysRequired>2</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_1KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -266,7 +267,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
<daysRequired>3</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
<li>ARA_Incubator_2_Reward_Hediffs</li>
@@ -281,7 +281,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Facehugger</pawnKind>
<daysRequired>2</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_4KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -297,7 +296,6 @@
<li>
<pawnKind>ARA_MimicNematodeShamblerSwarmer</pawnKind>
<daysRequired>1</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_6MEN</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -313,7 +311,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Smokepop</pawnKind>
<daysRequired>6</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_5KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -329,7 +326,6 @@
<li>
<pawnKind>ArachnaeNode_Race_NeuroSwarm</pawnKind>
<daysRequired>10</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_6KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -345,7 +341,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Skyraider</pawnKind>
<daysRequired>6</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_2KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -361,7 +356,6 @@
<li>
<pawnKind>ArachnaeNode_Race_Praetorian</pawnKind>
<daysRequired>12</daysRequired>
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
<requiredResearch>ARA_Technology_7KYC</requiredResearch>
<extraHediffs>
<li>ARA_Incubator_1_Reward_Hediffs</li>
@@ -384,8 +378,8 @@
<glowColor>(113,141,117,0)</glowColor>
</li>
<li Class="ArachnaeSwarm.CompProperties_TemperatureRuinableDamage">
<minSafeTemperature>-10</minSafeTemperature>
<maxSafeTemperature>20</maxSafeTemperature>
<minSafeTemperature>6</minSafeTemperature>
<maxSafeTemperature>36</maxSafeTemperature>
<damagePerTick>0.015</damagePerTick>
</li>
</comps>
@@ -465,6 +459,10 @@
</li>
</modExtensions>
<costList>
<ARA_InsectJelly>25</ARA_InsectJelly>
</costList>
<!-- ITab配置 -->
<inspectorTabs>
<li>ArachnaeSwarm.ITab_EquipmentOotheca_Incubation</li>
@@ -476,7 +474,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -505,8 +503,8 @@
<glowColor>(113,141,117,0)</glowColor>
</li>
<li Class="ArachnaeSwarm.CompProperties_TemperatureRuinableDamage">
<minSafeTemperature>-10</minSafeTemperature>
<maxSafeTemperature>20</maxSafeTemperature>
<minSafeTemperature>6</minSafeTemperature>
<maxSafeTemperature>36</maxSafeTemperature>
<damagePerTick>0.015</damagePerTick>
</li>
</comps>
@@ -527,11 +525,13 @@
</shadowData>
</graphicData>
<size>(1,1)</size>
<designationCategory>ARA_Buildings</designationCategory>
<altitudeLayer>Building</altitudeLayer>
<passability>PassThroughOnly</passability>
<fillPercent>0.3</fillPercent>
<rotatable>false</rotatable>
<tickerType>Normal</tickerType>
<terrainAffordanceNeeded>ARA_Incubator_Nutrient_Solution</terrainAffordanceNeeded>
<statBases>
<MarketValue>2000</MarketValue>
<MaxHitPoints>50</MaxHitPoints>
@@ -545,6 +545,10 @@
<ThingDef>ARA_Gene_Essence</ThingDef>
</descriptionHyperlinks>
<costList>
<ARA_InsectJelly>25</ARA_InsectJelly>
</costList>
<comps>
<!-- The new, GrowthVat-style fuel component -->
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
@@ -576,12 +580,23 @@
<productionTicksPerResearchPoint>30</productionTicksPerResearchPoint>
</li>
<li Class="ArachnaeSwarm.CompProperties_TemperatureRuinableDamage">
<minSafeTemperature>-30</minSafeTemperature>
<maxSafeTemperature>55</maxSafeTemperature>
<minSafeTemperature>6</minSafeTemperature>
<maxSafeTemperature>36</maxSafeTemperature>
<progressPerDegreePerTick>0.00005</progressPerDegreePerTick>
<damagePerTick>0.005</damagePerTick>
<recoveryRate>0.001</recoveryRate>
</li>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
<allowedRaces>
<li>ArachnaeNode_Race_WeaponSmith</li>
</allowedRaces>
</li>
</comps>
</ThingDef>
</Defs>

View File

@@ -65,7 +65,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>

View File

@@ -290,7 +290,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -439,7 +439,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>
@@ -611,7 +611,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>

View File

@@ -41,7 +41,7 @@
<comps>
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
<maxMaintenance>100</maxMaintenance>
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
<maintenanceDecayPerDay>85</maintenanceDecayPerDay>
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
<warningThreshold>0.2</warningThreshold>
<assignJobCheckInterval>1800</assignJobCheckInterval>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<LanguageData>
<!-- ===== 消息通知 ===== -->
<ARA_CorpseConverter.InsufficientFuel>生物质不足,无法进行尸体转换</ARA_CorpseConverter.InsufficientFuel>
<ARA_CorpseConverter.InsufficientFuelForMarking>生物质不足,无法标记拆除</ARA_CorpseConverter.InsufficientFuelForMarking>
<ARA_CorpseConverter.StockpileCreated>已创建尸体储存区,包含{0}个单元格</ARA_CorpseConverter.StockpileCreated>
<ARA_CorpseConverter.AutoMarkEnabled>自动标记拆除功能已启用</ARA_CorpseConverter.AutoMarkEnabled>
<ARA_CorpseConverter.AutoMarkDisabled>自动标记拆除功能已禁用</ARA_CorpseConverter.AutoMarkDisabled>
<!-- ===== 检查字符串(格式化) ===== -->
<ARA_CorpseConverter.Power>电力:{0}</ARA_CorpseConverter.Power>
<ARA_CorpseConverter.Fuel>生物质:{0} / {1}</ARA_CorpseConverter.Fuel>
<ARA_CorpseConverter.FuelPerConversion>每次转换消耗生物质:{0}</ARA_CorpseConverter.FuelPerConversion>
<ARA_CorpseConverter.NoFuelComponent>未找到生物质组件!</ARA_CorpseConverter.NoFuelComponent>
<ARA_CorpseConverter.WorkingProgress>工作中:{0}</ARA_CorpseConverter.WorkingProgress>
<ARA_CorpseConverter.TargetCorpse>目标尸体:{0}</ARA_CorpseConverter.TargetCorpse>
<ARA_CorpseConverter.NextConversion>下次转换:{0}天后</ARA_CorpseConverter.NextConversion>
<ARA_CorpseConverter.ConversionRadius>转换半径:{0}格</ARA_CorpseConverter.ConversionRadius>
<!-- ===== Gizmo按钮 ===== -->
<ARA_CorpseConverter.CreateStockpile>创建尸体储存区</ARA_CorpseConverter.CreateStockpile>
<ARA_CorpseConverter.CreateStockpileDesc>在转换器范围内创建尸体储存区,便于集中尸体进行转换</ARA_CorpseConverter.CreateStockpileDesc>
<ARA_CorpseConverter.ToggleAutoMark>切换自动标记</ARA_CorpseConverter.ToggleAutoMark>
<ARA_CorpseConverter.ToggleAutoMarkDesc>启用或禁用自动标记拆除功能。启用后,设备会定期标记范围内的目标建筑为拆除。</ARA_CorpseConverter.ToggleAutoMarkDesc>
<!-- ===== 开发模式按钮 ===== -->
<DEV_TestConversion>DEV: Test Conversion</DEV_TestConversion>
<DEV_ResetTimer>DEV: Reset Timer</DEV_ResetTimer>
<DEV_TestMarking>DEV: Test Marking</DEV_TestMarking>
<!-- ===== 系统消息 ===== -->
<No_valid_corpses_found>未找到有效尸体</No_valid_corpses_found>
<No_valid_buildings_found>未找到有效建筑</No_valid_buildings_found>
<!-- ===== 储存区标签 ===== -->
<ARA_CorpseConverter_Stockpile>尸体转换区</ARA_CorpseConverter_Stockpile>
</LanguageData>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<LanguageData>
<!-- ===== 消息通知 ===== -->
<ARA_TerrainChanger.InsufficientFuel>生物质不足,无法生成地形</ARA_TerrainChanger.InsufficientFuel>
<ARA_TerrainChanger.InsufficientFuelForMarking>生物质不足,无法标记拆除</ARA_TerrainChanger.InsufficientFuelForMarking>
<ARA_TerrainChanger.AutoMarkEnabled>自动标记拆除功能已启用</ARA_TerrainChanger.AutoMarkEnabled>
<ARA_TerrainChanger.AutoMarkDisabled>自动标记拆除功能已禁用</ARA_TerrainChanger.AutoMarkDisabled>
<!-- ===== Gizmo按钮 ===== -->
<ARA_TerrainChanger.ToggleAutoMark>切换自动标记</ARA_TerrainChanger.ToggleAutoMark>
<ARA_TerrainChanger.ToggleAutoMarkDesc>启用或禁用自动标记拆除功能。启用后,该结构会定期呼叫附近的虫族收集分泌物。</ARA_TerrainChanger.ToggleAutoMarkDesc>
<!-- ===== 检查字符串(格式化) ===== -->
<ARA_TerrainChanger.Power>电力:{0}</ARA_TerrainChanger.Power>
<ARA_TerrainChanger.Fuel>生物质:{0} / {1}</ARA_TerrainChanger.Fuel>
<ARA_TerrainChanger.FuelPerChange>每次转换消耗生物质:{0}</ARA_TerrainChanger.FuelPerChange>
<ARA_TerrainChanger.FuelPerMark>每次标记消耗生物质:{0}</ARA_TerrainChanger.FuelPerMark>
<ARA_TerrainChanger.NoFuelComponent>未找到生物质组件!</ARA_TerrainChanger.NoFuelComponent>
<ARA_TerrainChanger.WorkingProgress>工作中:{0}</ARA_TerrainChanger.WorkingProgress>
<ARA_TerrainChanger.TargetCell>目标位置:{0}</ARA_TerrainChanger.TargetCell>
<ARA_TerrainChanger.NextChange>下次分泌:{0}天后</ARA_TerrainChanger.NextChange>
<ARA_TerrainChanger.TargetTerrain>目标地形:{0}</ARA_TerrainChanger.TargetTerrain>
<ARA_TerrainChanger.ChangeRadius>分泌半径:{0}格</ARA_TerrainChanger.ChangeRadius>
<ARA_TerrainChanger.AutoMarkStatus>自动标记:{0}</ARA_TerrainChanger.AutoMarkStatus>
<ARA_TerrainChanger.NextMark>下次标记:{0}天后</ARA_TerrainChanger.NextMark>
<ARA_TerrainChanger.MarkingProgress>标记中:{0}</ARA_TerrainChanger.MarkingProgress>
<ARA_TerrainChanger.MarkTarget>标记目标:{0}</ARA_TerrainChanger.MarkTarget>
<ARA_TerrainChanger.MarkRadius>标记半径:{0}格</ARA_TerrainChanger.MarkRadius>
<!-- ===== 状态标签 ===== -->
<ARA_TerrainChanger.Enabled>已启用</ARA_TerrainChanger.Enabled>
<ARA_TerrainChanger.Disabled>已禁用</ARA_TerrainChanger.Disabled>
</LanguageData>

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,25 +1,81 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_productstorage\\compproperties_productstorage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_productstorage\\compproperties_productstorage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\jobdriver_stripchitin.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_stripchitin\\compproperties_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\compproperties_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_stripchitin\\comp_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_stripchitin\\comp_chitinstripping.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\verbs\\verb_shootselfunderfoot.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:verbs\\verb_shootselfunderfoot.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_hediffcomp_topturret\\hediffcomp_topturret.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hediffcomp_topturret\\hediffcomp_topturret.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\roomrole\\roomroleworker_incubator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:roomrole\\roomroleworker_incubator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_compinteractiveproducer\\compresearchproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_compinteractiveproducer\\compresearchproducer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ara_hediffdefof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:ara_hediffdefof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_corpseconverter\\compcorpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_corpseconverter\\compcorpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_corpseconverter\\compproperties_corpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_corpseconverter\\compproperties_corpseconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_terrainchanger\\compterrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_terrainchanger\\compterrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_terrainchanger\\compproperties_terrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_terrainchanger\\compproperties_terrainchanger.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\wula_mutifuelspawner\\comprefuelablenutrition_withkey.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\wula_mutifuelspawner\\comprefuelablenutrition_withkey.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_building_refuelingvat\\building_refuelingvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_ootheca\\itab_ootheca_incubation.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\itab_ootheca_incubation.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\compproperties_incubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_ootheca\\oothecaincubatorextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\oothecaincubatorextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_ootheca\\building_ootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_equipmentootheca\\compproperties_equipmentincubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\compproperties_equipmentincubatordata.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
@@ -30,76 +86,245 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"SelectedChildIndex": 1,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "CompProperties_ProductStorage.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"RelativeToolTip": "Building_Comps\\ARA_ProductStorage\\CompProperties_ProductStorage.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABQAAAAMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T08:35:48.647Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CompProperties_IncubatorData.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"ViewState": "AgIAAP4AAAAAAAAAAAAWwAIBAABCAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T08:17:40.867Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "ITab_Ootheca_Incubation.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\ITab_Ootheca_Incubation.cs",
"ViewState": "AgIAAJUAAAAAAAAAAAAewMkAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T08:14:08.752Z",
"EditorCaption": ""
},
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "Building_EquipmentOotheca.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ViewState": "AgIAALgCAAAAAAAAAAAAAMQCAAAjAAAAAAAAAA==",
"DocumentIndex": 0,
"Title": "JobDriver_StripChitin.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs*",
"RelativeToolTip": "Jobs\\JobDriver_StripChitin\\JobDriver_StripChitin.cs*",
"ViewState": "AgIAAFcAAAAAAAAAAAAAAHMAAAAoAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T08:13:46.678Z",
"WhenOpened": "2025-12-16T15:50:38.09Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CompProperties_ChitinStripping.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
"RelativeToolTip": "Jobs\\JobDriver_StripChitin\\CompProperties_ChitinStripping.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T15:50:04.277Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "Building_RefuelingVat.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"RelativeToolTip": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"ViewState": "AgIAAP4AAAAAAAAAAAAewA8BAAAAAAAAAAAAAA==",
"Title": "Comp_ChitinStripping.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
"RelativeToolTip": "Jobs\\JobDriver_StripChitin\\Comp_ChitinStripping.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAABWAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T04:00:20.165Z",
"WhenOpened": "2025-12-16T15:49:51.675Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "Verb_ShootSelfUnderfoot.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Verbs\\Verb_ShootSelfUnderfoot.cs",
"RelativeDocumentMoniker": "Verbs\\Verb_ShootSelfUnderfoot.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Verbs\\Verb_ShootSelfUnderfoot.cs",
"RelativeToolTip": "Verbs\\Verb_ShootSelfUnderfoot.cs",
"ViewState": "AgIAAJAAAAAAAAAAAAAcwJwAAAAoAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T15:07:22.127Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "HediffComp_TopTurret.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
"RelativeDocumentMoniker": "Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
"RelativeToolTip": "Hediffs\\ARA_HediffComp_TopTurret\\HediffComp_TopTurret.cs",
"ViewState": "AgIAACcBAAAAAAAAAAAkwD0BAAAjAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T14:52:46.325Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "RoomRoleWorker_Incubator.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\RoomRole\\RoomRoleWorker_Incubator.cs",
"RelativeDocumentMoniker": "RoomRole\\RoomRoleWorker_Incubator.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\RoomRole\\RoomRoleWorker_Incubator.cs",
"RelativeToolTip": "RoomRole\\RoomRoleWorker_Incubator.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABsAAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T14:32:31.389Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "CompResearchProducer.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
"RelativeToolTip": "Building_Comps\\ARA_CompInteractiveProducer\\CompResearchProducer.cs",
"ViewState": "AgIAAAAAAAAAAAAAAADwvy0AAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T14:29:05.969Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "CompCorpseConverter.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
"RelativeToolTip": "Building_Comps\\ARA_CorpseConverter\\CompCorpseConverter.cs",
"ViewState": "AgIAABwDAAAAAAAAAAAIwCoDAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T12:23:40.696Z"
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "ARA_HediffDefOf.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_HediffDefOf.cs",
"RelativeDocumentMoniker": "ARA_HediffDefOf.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_HediffDefOf.cs",
"RelativeToolTip": "ARA_HediffDefOf.cs",
"ViewState": "AgIAAAAAAAAAAAAAAADwvy0AAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-15T17:32:18.493Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "CompProperties_CorpseConverter.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
"RelativeToolTip": "Building_Comps\\ARA_CorpseConverter\\CompProperties_CorpseConverter.cs",
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T12:23:39.636Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "CompRefuelableNutrition_WithKey.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
"RelativeDocumentMoniker": "Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
"RelativeToolTip": "Building_Comps\\WULA_MutiFuelSpawner\\CompRefuelableNutrition_WithKey.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAACUAAABAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T10:38:33.135Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "CompTerrainChanger.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
"RelativeToolTip": "Building_Comps\\ARA_TerrainChanger\\CompTerrainChanger.cs",
"ViewState": "AgIAAK0CAAAAAAAAAAAcwPYCAAAMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T10:30:16.921Z"
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "CompProperties_TerrainChanger.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
"RelativeToolTip": "Building_Comps\\ARA_TerrainChanger\\CompProperties_TerrainChanger.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T10:30:15.601Z"
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "Building_RefuelingVat.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"RelativeToolTip": "Building_Comps\\ARA_Building_RefuelingVat\\Building_RefuelingVat.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T10:28:54.756Z"
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "CompProperties_IncubatorData.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\CompProperties_IncubatorData.cs",
"ViewState": "AgIAANcAAAAAAAAAAIA1wPoAAAAxAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T04:37:03.042Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "OothecaIncubatorExtension.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\OothecaIncubatorExtension.cs",
"ViewState": "AgIAAAAAAAAAAAAAAADwvxUAAABBAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-16T04:36:59.394Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "Building_EquipmentOotheca.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\Building_EquipmentOotheca.cs",
"ViewState": "AgIAACcAAAAAAAAAAAAAADoDAABSAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-15T18:22:14.171Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "Building_Ootheca.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
"ViewState": "AgIAALcCAAAAAAAAAAAewNgCAAAVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-15T18:22:12.217Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "CompProperties_EquipmentIncubatorData.cs",
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
"RelativeDocumentMoniker": "Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
"RelativeToolTip": "Buildings\\Building_EquipmentOotheca\\CompProperties_EquipmentIncubatorData.cs",
"ViewState": "AgIAAA4AAAAAAAAAAADwvyYAAAAaAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-12-15T17:55:40.041Z"
}
]
}

View File

@@ -37,4 +37,14 @@ namespace ArachnaeSwarm
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_EffecterDefOf));
}
}
[DefOf]
public static class ARA_SoundDefOf
{
public static SoundDef AcidSpray_Resolve;
static ARA_SoundDefOf()
{
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_SoundDefOf));
}
}
}

View File

@@ -124,13 +124,15 @@
<Compile Include="Buildings\Building_Ootheca\ITab_Ootheca_Incubation.cs" />
<Compile Include="Buildings\Building_Ootheca\JobDriver_OperateIncubator.cs" />
<Compile Include="Buildings\Building_Ootheca\OothecaIncubatorExtension.cs" />
<Compile Include="Buildings\Building_Ootheca\RoomRoleWorker_Incubator.cs" />
<Compile Include="RoomRole\RoomRoleWorker_Incubator.cs" />
<Compile Include="Buildings\Building_TurretGunHasSpeed.cs" />
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\Building_RefuelingVat.cs" />
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\CompProperties_RefuelingVat.cs" />
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\CompRefuelingVat.cs" />
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\CompResearchProducer.cs" />
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\JobDriver_StartResearchProduction.cs" />
<Compile Include="Building_Comps\ARA_CorpseConverter\CompCorpseConverter.cs" />
<Compile Include="Building_Comps\ARA_CorpseConverter\CompProperties_CorpseConverter.cs" />
<Compile Include="Building_Comps\ARA_ForwardClearance\CompForwardClearance.cs" />
<Compile Include="Building_Comps\ARA_ForwardClearance\CompProperties_ForwardClearance.cs" />
<Compile Include="Building_Comps\ARA_ForwardClearance\PlaceWorker_ForwardClearance.cs" />
@@ -138,6 +140,8 @@
<Compile Include="Building_Comps\ARA_ProductStorage\CompProperties_ProductStorage.cs" />
<Compile Include="Building_Comps\ARA_SwarmMaintenance\CompProperties_SwarmMaintenance.cs" />
<Compile Include="Building_Comps\ARA_SwarmMaintenance\Comp_SwarmMaintenance.cs" />
<Compile Include="Building_Comps\ARA_TerrainChanger\CompProperties_TerrainChanger.cs" />
<Compile Include="Building_Comps\ARA_TerrainChanger\CompTerrainChanger.cs" />
<Compile Include="Building_Comps\CompBreakdownDisabler.cs" />
<Compile Include="EventSystem\CompOpenCustomUI.cs" />
<Compile Include="EventSystem\Condition.cs" />
@@ -195,6 +199,7 @@
<Compile Include="Storyteller\RaidWavePoolDef.cs" />
<Compile Include="Flyover\ThingclassFlyOver.cs" />
<Compile Include="Flyover\ARA_FlyOverDropPod\CompProperties_FlyOverDropPod.cs" />
<Compile Include="Verbs\Verb_ShootSelfUnderfoot.cs" />
<Compile Include="Verbs\Verb_ShootWithOffset.cs" />
<Compile Include="Abilities\ARA_ShowTemperatureRange\CompAbilityEffect_AbilityShowTemperatureRange.cs" />
<Compile Include="Abilities\ARA_ShowTemperatureRange\CompProperties_AbilityShowTemperatureRange.cs" />

View File

@@ -138,7 +138,7 @@ namespace ArachnaeSwarm
if (!Destroyed)
{
// 销毁建筑
Destroy(DestroyMode.Vanish);
Kill();
}
}
@@ -272,7 +272,7 @@ namespace ArachnaeSwarm
DamageInfo acidDamage = new DamageInfo(
acidDamageDef,
1000f, // 每次1.5点伤害
1.5f, // 每次1.5点伤害
2f, // 护甲穿透
-1f, // 随机角度
null, // 将建筑设为伤害来源

View File

@@ -0,0 +1,967 @@
// File: Comps/CompCorpseConverter.cs
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.Sound;
using System.Text;
using System.Linq;
using Verse.AI;
namespace ArachnaeSwarm
{
public class CompCorpseConverter : ThingComp
{
// 属性引用
private CompProperties_CorpseConverter Props => (CompProperties_CorpseConverter)props;
// 状态变量
private int ticksUntilNextConversion;
private bool isWorking = false;
private int workTicksRemaining = 0;
private Corpse targetCorpse = null;
private Effecter effecter;
private Effecter conversionEffecter;
// --- 新增:自动标记拆除状态 ---
private bool autoMarkForDeconstructionEnabled = true;
private int ticksUntilNextMarkDeconstruction;
private bool isMarking = false;
private int markingTicksRemaining = 0;
private Thing markingTargetBuilding = null;
private Effecter markingEffecter;
// 当前工作速度乘数
private float currentWorkSpeedMultiplier = 1.0f;
// 缓存燃料组件
private CompRefuelableNutrition_WithKey compRefuelable;
private bool refuelableComponentCached = false;
// 储存区图标缓存
private static readonly CachedTexture CreateCorpseStockpileIcon = new CachedTexture("UI/Icons/CorpseStockpileZone");
// 临时列表
private List<IntVec3> tmpRadialCells = new List<IntVec3>();
// 获取径向单元格(转换半径内)
private IEnumerable<IntVec3> RadialCells => GenRadial.RadialCellsAround(parent.Position, Props.conversionRadius, useCenter: true);
// 获取燃料组件
private CompRefuelableNutrition_WithKey CompRefuelable
{
get
{
if (!refuelableComponentCached)
{
compRefuelable = parent.TryGetComp<CompRefuelableNutrition_WithKey>();
refuelableComponentCached = true;
}
return compRefuelable;
}
}
// 检查燃料是否充足
private bool HasSufficientFuel
{
get
{
if (!Props.requiresFuel)
return true;
if (CompRefuelable == null)
return false;
return CompRefuelable.Fuel >= Props.minFuelToOperate;
}
}
// 检查是否有足够的燃料用于标记
private bool HasSufficientFuelForMarking
{
get
{
if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
return true;
if (CompRefuelable == null)
return false;
return CompRefuelable.Fuel >= Props.fuelConsumptionPerMark;
}
}
// 消耗燃料
private bool ConsumeFuelIfNeeded()
{
if (!Props.requiresFuel || Props.fuelConsumptionPerConversion <= 0)
return true;
if (CompRefuelable == null)
return false;
if (CompRefuelable.Fuel >= Props.fuelConsumptionPerConversion)
{
CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerConversion);
return true;
}
return false;
}
// 消耗标记燃料
private bool ConsumeMarkingFuelIfNeeded()
{
if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
return true;
if (CompRefuelable == null)
return false;
if (CompRefuelable.Fuel >= Props.fuelConsumptionPerMark)
{
CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerMark);
return true;
}
return false;
}
// 获取电源状态
private bool HasPower
{
get
{
if (!Props.requiresPower)
return true;
var compPower = parent.TryGetComp<CompPowerTrader>();
return compPower != null && compPower.PowerOn;
}
}
// 获取房间
private Room GetRoom()
{
var map = parent.Map;
if (map == null)
return null;
return parent.Position.GetRoom(map);
}
// 检查是否满足操作条件
private bool CanOperate()
{
// 检查是否有电
if (Props.requiresPower && !HasPower)
return false;
// 检查是否有足够的燃料
if (Props.requiresFuel && !HasSufficientFuel)
return false;
// 检查是否在房间内(如果需要)
if (Props.requiresRoom)
{
var room = GetRoom();
if (room == null || !room.ProperRoom)
return false;
// 检查房间评分
if (room.GetStat(RoomStatDefOf.Impressiveness) < Props.minRoomScore)
return false;
}
return true;
}
// 检查是否可以执行标记操作
private bool CanMarkForDeconstruction()
{
if (!Props.enableAutoMarkForDeconstruction || !autoMarkForDeconstructionEnabled)
return false;
if (!CanOperate())
return false;
// 检查标记燃料
if (Props.requiresFuel && !HasSufficientFuelForMarking)
return false;
return true;
}
// 获取有效的目标尸体
private bool TryGetValidTargetCorpse(out Corpse result)
{
result = null;
var map = parent.Map;
if (map == null)
return false;
// 获取搜索范围
var center = parent.Position;
int radius = Mathf.CeilToInt(Props.conversionRadius);
// 获取房间(如果需要)
Room parentRoom = null;
if (Props.requiresRoom)
{
parentRoom = GetRoom();
if (parentRoom == null)
return false;
}
// 收集所有候选尸体
List<Corpse> candidateCorpses = new List<Corpse>();
for (int x = -radius; x <= radius; x++)
{
for (int z = -radius; z <= radius; z++)
{
IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
if (!cell.InBounds(map))
continue;
// 检查距离
float distance = cell.DistanceTo(center);
if (distance > Props.conversionRadius)
continue;
// 检查房间(如果需要)
if (Props.requiresRoom)
{
var cellRoom = cell.GetRoom(map);
if (cellRoom == null || cellRoom != parentRoom)
continue;
}
// 获取单元格中的所有东西
var things = cell.GetThingList(map);
foreach (var thing in things)
{
if (thing is Corpse corpse)
{
// 检查尸体是否腐烂
if (corpse.GetRotStage() == RotStage.Fresh || corpse.GetRotStage() == RotStage.Rotting)
{
// 检查是否在可接受尸体列表中(如果有定义)
if (Props.acceptedCorpseDefs != null && Props.acceptedCorpseDefs.Count > 0)
{
if (!Props.acceptedCorpseDefs.Contains(corpse.def))
continue;
}
// 排除机械族尸体(如果启用)
if (Props.excludeMechanoidCorpses)
{
var pawn = corpse.InnerPawn;
if (pawn != null && pawn.RaceProps.IsMechanoid)
{
continue; // 跳过机械族尸体
}
}
candidateCorpses.Add(corpse);
}
}
}
}
}
if (candidateCorpses.Count == 0)
return false;
// 选择最近的尸体
float closestDistance = float.MaxValue;
Corpse closestCorpse = null;
foreach (var corpse in candidateCorpses)
{
float distance = corpse.Position.DistanceTo(center);
if (distance < closestDistance)
{
closestDistance = distance;
closestCorpse = corpse;
}
}
if (closestCorpse != null)
{
result = closestCorpse;
return true;
}
return false;
}
// 获取有效的标记拆除建筑
private bool TryGetValidMarkingBuilding(out Thing result)
{
result = null;
var map = parent.Map;
if (map == null)
return false;
// 获取搜索范围
var center = parent.Position;
int radius = Mathf.CeilToInt(Props.markDeconstructionRadius);
// 获取房间(如果需要)
Room parentRoom = null;
if (Props.requiresRoom)
{
parentRoom = GetRoom();
if (parentRoom == null)
return false;
}
// 收集所有候选建筑
List<Thing> candidateBuildings = new List<Thing>();
for (int x = -radius; x <= radius; x++)
{
for (int z = -radius; z <= radius; z++)
{
IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
if (!cell.InBounds(map))
continue;
// 检查距离
float distance = cell.DistanceTo(center);
if (distance > Props.markDeconstructionRadius)
continue;
// 检查房间(如果需要)
if (Props.requiresRoom)
{
var cellRoom = cell.GetRoom(map);
if (cellRoom == null || cellRoom != parentRoom)
continue;
}
// 获取单元格中的所有东西
var things = cell.GetThingList(map);
foreach (var thing in things)
{
// 检查是否是目标建筑
if (thing.def == Props.targetThingDef)
{
// 检查是否已经标记了拆除
if (map.designationManager.DesignationOn(thing, DesignationDefOf.Deconstruct) != null)
continue;
candidateBuildings.Add(thing);
}
}
}
}
if (candidateBuildings.Count == 0)
return false;
// 选择最近的建筑
float closestDistance = float.MaxValue;
Thing closestBuilding = null;
foreach (var building in candidateBuildings)
{
float distance = building.Position.DistanceTo(center);
if (distance < closestDistance)
{
closestDistance = distance;
closestBuilding = building;
}
}
if (closestBuilding != null)
{
result = closestBuilding;
return true;
}
return false;
}
// 开始工作
private void StartWorking(Corpse targetCorpse)
{
this.targetCorpse = targetCorpse;
this.isWorking = true;
// 计算工作时间(基于距离)
float distance = targetCorpse.Position.DistanceTo(parent.Position);
float workTimeFactor = 1f + (distance / Props.conversionRadius) * 0.5f; // 距离越远,时间越长
int baseWorkTime = Mathf.RoundToInt(Props.conversionInterval * 0.1f); // 工作时间为间隔的10%
workTicksRemaining = Mathf.RoundToInt(baseWorkTime * workTimeFactor / currentWorkSpeedMultiplier);
// 播放声音
if (Props.workingSound != null)
{
Props.workingSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
// 启动工作效果器
if (Props.showVisualEffects && Props.workingEffecter != null)
{
effecter = Props.workingEffecter.Spawn();
effecter.Trigger(parent, targetCorpse);
}
// 启动转换效果器(在尸体上)
if (Props.showVisualEffects && Props.conversionEffecter != null)
{
conversionEffecter = Props.conversionEffecter.Spawn();
conversionEffecter.Trigger(targetCorpse, parent);
}
}
// 开始标记工作
private void StartMarking(Thing targetBuilding)
{
this.markingTargetBuilding = targetBuilding;
this.isMarking = true;
// 计算标记时间(基于距离)
float distance = targetBuilding.Position.DistanceTo(parent.Position);
float workTimeFactor = 1f + (distance / Props.markDeconstructionRadius) * 0.5f;
int baseMarkTime = Mathf.RoundToInt(Props.markDeconstructionInterval * 0.05f); // 标记时间为间隔的5%
markingTicksRemaining = Mathf.RoundToInt(baseMarkTime * workTimeFactor / currentWorkSpeedMultiplier);
// 播放标记声音
if (Props.markSound != null)
{
Props.markSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
}
// 完成转换
private void CompleteConversion()
{
var map = parent.Map;
if (map == null || targetCorpse == null || targetCorpse.Destroyed || !targetCorpse.Spawned)
{
ResetWorkState();
return;
}
// 检查并消耗燃料
if (!ConsumeFuelIfNeeded())
{
Messages.Message("ARA_CorpseConverter.InsufficientFuel".Translate(),
new TargetInfo(targetCorpse.Position, map), MessageTypeDefOf.NegativeEvent);
ResetWorkState();
return;
}
// 记录尸体的位置和信息
IntVec3 corpsePosition = targetCorpse.Position;
string corpseName = targetCorpse.InnerPawn?.LabelShort ?? "unknown";
// 移除尸体
targetCorpse.Destroy(DestroyMode.Vanish);
// 播放转换声音
if (Props.conversionSound != null)
{
Props.conversionSound.PlayOneShot(new TargetInfo(corpsePosition, map));
}
// 生成目标建筑
if (Props.targetThingDef != null)
{
Thing convertedThing = ThingMaker.MakeThing(Props.targetThingDef);
// 检查是否是建筑
if (convertedThing.def.category == ThingCategory.Building)
{
// 尝试在尸体原位置生成
GenSpawn.Spawn(convertedThing, corpsePosition, map);
// 播放完成声音
if (Props.completionSound != null)
{
Props.completionSound.PlayOneShot(new TargetInfo(corpsePosition, map));
}
// 显示消息(仅开发模式)
if (Prefs.DevMode)
{
Log.Message($"[CorpseConverter] Converted {corpseName} at {corpsePosition} to {convertedThing.LabelCap}");
}
}
else
{
Log.Error($"CorpseConverter: targetThingDef {Props.targetThingDef.defName} is not a building! Cannot spawn.");
}
}
ResetWorkState();
}
// 完成标记工作
private void CompleteMarking()
{
var map = parent.Map;
if (map == null || markingTargetBuilding == null || markingTargetBuilding.Destroyed || !markingTargetBuilding.Spawned)
{
ResetMarkingState();
return;
}
// 检查并消耗标记燃料
if (!ConsumeMarkingFuelIfNeeded())
{
Messages.Message("ARA_CorpseConverter.InsufficientFuelForMarking".Translate(),
new TargetInfo(markingTargetBuilding.Position, map), MessageTypeDefOf.NegativeEvent);
ResetMarkingState();
return;
}
// 确保是目标建筑(安全检查)
if (markingTargetBuilding.def != Props.targetThingDef)
{
ResetMarkingState();
return;
}
// 添加拆除标记
map.designationManager.AddDesignation(new Designation(markingTargetBuilding, DesignationDefOf.Deconstruct));
// 播放完成声音
if (Props.markCompleteSound != null)
{
Props.markCompleteSound.PlayOneShot(new TargetInfo(markingTargetBuilding.Position, map));
}
// 显示消息(仅开发模式)
if (Prefs.DevMode)
{
Log.Message($"[CorpseConverter] Marked building at {markingTargetBuilding.Position} ({markingTargetBuilding.LabelCap}) for deconstruction");
}
ResetMarkingState();
}
// 重置工作状态
private void ResetWorkState()
{
isWorking = false;
workTicksRemaining = 0;
targetCorpse = null;
// 清理效果器
if (effecter != null)
{
effecter.Cleanup();
effecter = null;
}
if (conversionEffecter != null)
{
conversionEffecter.Cleanup();
conversionEffecter = null;
}
}
// 重置标记状态
private void ResetMarkingState()
{
isMarking = false;
markingTicksRemaining = 0;
markingTargetBuilding = null;
// 清理标记效果器
if (markingEffecter != null)
{
markingEffecter.Cleanup();
markingEffecter = null;
}
}
// 更新工作速度
private void UpdateWorkSpeed()
{
float multiplier = 1.0f;
if (Props.requiresPower && HasPower)
{
multiplier *= Props.poweredWorkSpeedMultiplier;
}
if (Props.requiresFuel && HasSufficientFuel)
{
// 燃料充足时可能有额外的速度加成
}
currentWorkSpeedMultiplier = multiplier;
}
// Tick更新
public override void CompTick()
{
base.CompTick();
// --- 处理尸体转换 ---
if (isWorking)
{
workTicksRemaining--;
if (workTicksRemaining <= 0)
{
CompleteConversion();
}
// 更新效果器
if (effecter != null)
{
effecter.EffectTick(parent, targetCorpse);
}
if (conversionEffecter != null)
{
conversionEffecter.EffectTick(targetCorpse, parent);
}
}
else if (CanOperate())
{
UpdateWorkSpeed();
// 等待下一次转换
if (ticksUntilNextConversion <= 0)
{
// 尝试找到有效目标尸体
if (TryGetValidTargetCorpse(out Corpse target))
{
// 在开始工作前再次检查燃料
if (Props.requiresFuel && Props.fuelConsumptionPerConversion > 0)
{
if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerConversion)
{
// 燃料不足,重置计时器但跳过这次工作
ticksUntilNextConversion = Mathf.RoundToInt(Props.conversionInterval / currentWorkSpeedMultiplier);
return;
}
}
StartWorking(target);
}
// 重置计时器,无论是否成功找到目标
ticksUntilNextConversion = Mathf.RoundToInt(Props.conversionInterval / currentWorkSpeedMultiplier);
}
else
{
ticksUntilNextConversion--;
}
}
else
{
if (isWorking)
{
ResetWorkState();
}
}
// --- 处理自动标记拆除 ---
if (isMarking)
{
markingTicksRemaining--;
if (markingTicksRemaining <= 0)
{
CompleteMarking();
}
// 更新标记效果器
if (markingEffecter != null)
{
markingEffecter.EffectTick(parent, markingTargetBuilding);
}
}
else if (CanMarkForDeconstruction())
{
// 等待下一次标记
if (ticksUntilNextMarkDeconstruction <= 0)
{
// 尝试找到有效标记建筑
if (TryGetValidMarkingBuilding(out Thing target))
{
// 在开始标记前再次检查燃料
if (Props.requiresFuel && Props.fuelConsumptionPerMark > 0)
{
if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerMark)
{
// 燃料不足,重置计时器但跳过这次标记
ticksUntilNextMarkDeconstruction = Mathf.RoundToInt(Props.markDeconstructionInterval / currentWorkSpeedMultiplier);
return;
}
}
StartMarking(target);
}
// 重置计时器,无论是否成功找到目标
ticksUntilNextMarkDeconstruction = Mathf.RoundToInt(Props.markDeconstructionInterval / currentWorkSpeedMultiplier);
}
else
{
ticksUntilNextMarkDeconstruction--;
}
}
}
// 防止长时间不工作
public override void CompTickRare()
{
base.CompTickRare();
if (!isWorking && ticksUntilNextConversion > Props.conversionInterval * 10)
{
// 防止计时器溢出
ticksUntilNextConversion = Props.conversionInterval;
}
if (!isMarking && ticksUntilNextMarkDeconstruction > Props.markDeconstructionInterval * 10)
{
// 防止标记计时器溢出
ticksUntilNextMarkDeconstruction = Props.markDeconstructionInterval;
}
}
// 保存/加载
public override void PostExposeData()
{
base.PostExposeData();
// 尸体转换状态
Scribe_Values.Look(ref ticksUntilNextConversion, "ticksUntilNextConversion", Props.conversionInterval);
Scribe_Values.Look(ref isWorking, "isWorking", false);
Scribe_Values.Look(ref workTicksRemaining, "workTicksRemaining", 0);
// 标记拆除状态
Scribe_Values.Look(ref autoMarkForDeconstructionEnabled, "autoMarkForDeconstructionEnabled", true);
Scribe_Values.Look(ref ticksUntilNextMarkDeconstruction, "ticksUntilNextMarkDeconstruction", Props.markDeconstructionInterval);
Scribe_Values.Look(ref isMarking, "isMarking", false);
Scribe_Values.Look(ref markingTicksRemaining, "markingTicksRemaining", 0);
// 保存目标尸体的引用
if (Scribe.mode == LoadSaveMode.Saving)
{
bool hasTarget = targetCorpse != null && targetCorpse.Spawned;
Scribe_Values.Look(ref hasTarget, "hasTarget", false);
if (hasTarget)
{
Scribe_References.Look(ref targetCorpse, "targetCorpse");
}
bool hasMarkingTarget = markingTargetBuilding != null && markingTargetBuilding.Spawned;
Scribe_Values.Look(ref hasMarkingTarget, "hasMarkingTarget", false);
if (hasMarkingTarget)
{
Scribe_References.Look(ref markingTargetBuilding, "markingTargetBuilding");
}
}
else if (Scribe.mode == LoadSaveMode.LoadingVars)
{
bool hasTarget = false;
Scribe_Values.Look(ref hasTarget, "hasTarget", false);
if (hasTarget)
{
Scribe_References.Look(ref targetCorpse, "targetCorpse");
}
bool hasMarkingTarget = false;
Scribe_Values.Look(ref hasMarkingTarget, "hasMarkingTarget", false);
if (hasMarkingTarget)
{
Scribe_References.Look(ref markingTargetBuilding, "markingTargetBuilding");
}
}
}
// 检查字符串
public override string CompInspectStringExtra()
{
var builder = new StringBuilder();
if (Props.requiresPower)
{
builder.AppendLine("ARA_CorpseConverter.Power".Translate(HasPower ? "On".Translate() : "Off".Translate()));
}
if (Props.requiresFuel)
{
if (CompRefuelable != null)
{
builder.AppendLine("ARA_CorpseConverter.Fuel".Translate(
CompRefuelable.Fuel.ToString("F1"),
CompRefuelable.TargetFuelLevel.ToString("F1")));
if (Props.fuelConsumptionPerConversion > 0)
{
builder.AppendLine("ARA_CorpseConverter.FuelPerConversion".Translate(
Props.fuelConsumptionPerConversion.ToString("F1")));
}
}
else
{
builder.AppendLine("ARA_CorpseConverter.NoFuelComponent".Translate());
}
}
if (isWorking)
{
float progressPercent = 1f - ((float)workTicksRemaining / (Props.conversionInterval * 0.1f));
builder.AppendLine("ARA_CorpseConverter.WorkingProgress".Translate(
progressPercent.ToStringPercent()));
if (targetCorpse != null)
{
builder.AppendLine("ARA_CorpseConverter.TargetCorpse".Translate(
targetCorpse.InnerPawn?.LabelShort ?? "unknown"));
}
}
else
{
float daysUntilConversion = ticksUntilNextConversion / 60000f;
builder.AppendLine("ARA_CorpseConverter.NextConversion".Translate(
daysUntilConversion.ToString("F1")));
}
builder.AppendLine("ARA_CorpseConverter.ConversionRadius".Translate(
Props.conversionRadius.ToString("F1")));
return builder.ToString().TrimEndNewlines();
}
// 切换自动标记功能
private void ToggleAutoMarking()
{
autoMarkForDeconstructionEnabled = !autoMarkForDeconstructionEnabled;
if (autoMarkForDeconstructionEnabled)
{
Messages.Message("ARA_CorpseConverter.AutoMarkEnabled".Translate(),
parent, MessageTypeDefOf.PositiveEvent);
}
else
{
Messages.Message("ARA_CorpseConverter.AutoMarkDisabled".Translate(),
parent, MessageTypeDefOf.NeutralEvent);
}
}
// 获取Gizmos
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (var gizmo in base.CompGetGizmosExtra())
{
yield return gizmo;
}
// 自动标记拆除切换按钮
if (Props.enableAutoMarkForDeconstruction && parent.Faction == Faction.OfPlayer)
{
yield return new Command_Toggle
{
defaultLabel = "ARA_CorpseConverter.ToggleAutoMark".Translate(),
defaultDesc = "ARA_CorpseConverter.ToggleAutoMarkDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Designators/Deconstruct", false) ?? BaseContent.BadTex,
isActive = () => autoMarkForDeconstructionEnabled,
toggleAction = ToggleAutoMarking,
hotKey = KeyBindingDefOf.Misc4
};
}
// 开发模式下的调试命令
if (DebugSettings.ShowDevGizmos)
{
yield return new Command_Action
{
defaultLabel = "DEV: Test Conversion",
action = delegate
{
if (TryGetValidTargetCorpse(out Corpse corpse))
{
StartWorking(corpse);
}
else
{
Messages.Message("No valid corpses found", parent, MessageTypeDefOf.RejectInput);
}
}
};
yield return new Command_Action
{
defaultLabel = "DEV: Reset Timer",
action = delegate
{
ticksUntilNextConversion = 0;
}
};
yield return new Command_Action
{
defaultLabel = "DEV: Test Marking",
action = delegate
{
if (TryGetValidMarkingBuilding(out Thing building))
{
StartMarking(building);
}
else
{
Messages.Message("No valid buildings found", parent, MessageTypeDefOf.RejectInput);
}
}
};
}
}
// 绘制选择时的额外效果
public override void PostDrawExtraSelectionOverlays()
{
base.PostDrawExtraSelectionOverlays();
if (Props.showRadius)
{
// 显示转换半径
GenDraw.DrawRadiusRing(parent.Position, Props.conversionRadius, Color.red);
// 显示标记半径(如果不同)
if (Props.markDeconstructionRadius != Props.conversionRadius)
{
GenDraw.DrawRadiusRing(parent.Position, Props.markDeconstructionRadius, new Color(1f, 0.5f, 0f, 0.5f));
}
}
}
// 建筑被销毁时清理
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
base.PostDestroy(mode, previousMap);
ResetWorkState();
ResetMarkingState();
}
// 建筑生成时初始化
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
refuelableComponentCached = false; // 重置缓存,重新获取组件
// 初始化计时器
if (!respawningAfterLoad)
{
ticksUntilNextConversion = Props.conversionInterval;
autoMarkForDeconstructionEnabled = Props.enableAutoMarkForDeconstruction;
ticksUntilNextMarkDeconstruction = Props.markDeconstructionInterval;
}
}
}
}

View File

@@ -0,0 +1,125 @@
// File: Comps/CompProperties_CorpseConverter.cs
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_CorpseConverter : CompProperties
{
// 转换目标物品定义(必须是建筑)
public ThingDef targetThingDef;
// 转换数量(每次转换生成多少个目标物品)
public int targetThingCount = 1;
// 基础转换间隔(游戏刻)
public int conversionInterval = 60000; // 默认1天
// 转换半径(以单元格为单位)
public float conversionRadius = 8f;
// 是否需要电源
public bool requiresPower = false;
// 电源开启时的工作速度乘数
public float poweredWorkSpeedMultiplier = 1.5f;
// 需要燃料
public bool requiresFuel = false;
// 每次转换消耗的燃料量
public float fuelConsumptionPerConversion = 5f;
// 最小燃料量要求(低于此值不工作)
public float minFuelToOperate = 0.1f;
// 接受哪些种类的尸体(可选,如果为空则接受所有尸体)
public List<ThingDef> acceptedCorpseDefs;
// 是否显示视觉效果
public bool showVisualEffects = true;
// 工作时的效果器
public EffecterDef workingEffecter;
// 转换时的效果器
public EffecterDef conversionEffecter;
// 工作时的声音
public SoundDef workingSound;
// 转换时的声音
public SoundDef conversionSound;
// 转换完成时的声音
public SoundDef completionSound;
// 是否需要房间
public bool requiresRoom = false;
// 需要的最低房间评分(可选)
public float minRoomScore = -9999f;
// 是否显示转换进度
public bool showProgress = true;
// 是否显示转换半径
public bool showRadius = true;
// --- 新增:自动标记拆除功能 ---
// 是否启用自动标记拆除功能
public bool enableAutoMarkForDeconstruction = true;
// 自动标记拆除间隔(游戏刻)
public int markDeconstructionInterval = 120000; // 默认2天
// 标记拆除半径(可以不同于转换半径)
public float markDeconstructionRadius = 8f;
// 每次标记消耗的燃料量(可选)
public float fuelConsumptionPerMark = 2f;
// 标记效果器
public EffecterDef markEffecter;
// 标记时的声音
public SoundDef markSound;
// 标记完成时的声音
public SoundDef markCompleteSound;
// 是否排除机械族尸体
public bool excludeMechanoidCorpses = true;
public CompProperties_CorpseConverter()
{
compClass = typeof(CompCorpseConverter);
}
// 验证配置
public override void ResolveReferences(ThingDef parentDef)
{
base.ResolveReferences(parentDef);
if (targetThingDef == null)
{
Log.Warning($"CompProperties_CorpseConverter on {parentDef.defName} has no targetThingDef specified!");
}
// 检查目标物品是否是建筑
if (targetThingDef != null && targetThingDef.category != ThingCategory.Building)
{
Log.Warning($"CompProperties_CorpseConverter on {parentDef.defName}: targetThingDef {targetThingDef.defName} is not a building, but auto-deconstruction requires a building!");
}
// 如果未指定标记半径,使用转换半径
if (markDeconstructionRadius <= 0)
{
markDeconstructionRadius = conversionRadius;
}
}
}
}

View File

@@ -323,8 +323,8 @@ namespace ArachnaeSwarm
// 只在玩家控制下显示
if (parent.Faction?.IsPlayer == true)
{
// 调试按钮:手动触发寻找维护者
if (Prefs.DevMode)
// 调试按钮:手动触发寻找维护者 - 仅在GodMode下显示
if (DebugSettings.godMode)
{
yield return new Command_Action
{

View File

@@ -0,0 +1,104 @@
// File: Comps/CompProperties_TerrainChanger.cs
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_TerrainChanger : CompProperties
{
// 目标地形定义
public TerrainDef targetTerrain;
// 基础改变间隔(游戏刻)
public int baseChangeInterval = 60000; // 默认1天
// 改变半径(以单元格为单位)
public float changeRadius = 5f;
// 是否只在房间内改变
public bool onlyInSameRoom = true;
// 是否优先改变最近的地形
public bool prioritizeClosest = true;
// 需要的最低房间评分(可选)
public float minRoomScore = -9999f;
// 是否需要电源
public bool requiresPower = false;
// 电源开启时的工作速度乘数
public float poweredWorkSpeedMultiplier = 2f;
// 需要燃料
public bool requiresFuel = false;
// 每次地形改变消耗的燃料量
public float fuelConsumptionPerChange = 1f;
// 最小燃料量要求(低于此值不工作)
public float minFuelToOperate = 0.1f;
// 可接受的地形类型列表(可选,如果为空则接受所有可通行地形)
public List<TerrainDef> acceptedTerrains;
// 是否显示视觉效果
public bool showVisualEffects = true;
// 效果器定义
public EffecterDef workingEffecter;
// 工作时的声音
public SoundDef workingSound;
// 完成时的声音
public SoundDef completionSound;
// --- 新增:自动标记拆除功能 ---
// 是否启用自动标记拆除功能
public bool enableAutoMarkForRemoval = true;
// 自动标记拆除间隔(游戏刻)
public int markRemovalInterval = 120000; // 默认2天
// 标记拆除半径(可以不同于改变半径)
public float markRemovalRadius = 5f;
// 每次标记消耗的燃料量(可选)
public float fuelConsumptionPerMark = 0.5f;
// 标记效果器
public EffecterDef markEffecter;
// 标记时的声音
public SoundDef markSound;
// 标记完成时的声音
public SoundDef markCompleteSound;
public CompProperties_TerrainChanger()
{
compClass = typeof(CompTerrainChanger);
}
// 验证配置
public override void ResolveReferences(ThingDef parentDef)
{
base.ResolveReferences(parentDef);
if (targetTerrain == null)
{
Log.Warning($"CompProperties_TerrainChanger on {parentDef.defName} has no targetTerrain specified!");
}
// 如果未指定标记半径,使用改变半径
if (markRemovalRadius <= 0)
{
markRemovalRadius = changeRadius;
}
}
}
}

View File

@@ -0,0 +1,825 @@
// File: Comps/CompTerrainChanger.cs
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.Sound;
using System.Text;
using Verse.AI;
namespace ArachnaeSwarm
{
public class CompTerrainChanger : ThingComp
{
// 属性引用
private CompProperties_TerrainChanger Props => (CompProperties_TerrainChanger)props;
// 状态变量
private int ticksUntilNextChange;
private bool isWorking = false;
private int workTicksRemaining = 0;
private IntVec3 targetCell = IntVec3.Invalid;
private Effecter effecter;
// --- 新增:自动标记拆除状态 ---
private bool autoMarkForRemovalEnabled = true;
private int ticksUntilNextMarkRemoval;
private bool isMarking = false;
private int markingTicksRemaining = 0;
private IntVec3 markingTargetCell = IntVec3.Invalid;
private Effecter markingEffecter;
// 当前工作速度乘数
private float currentWorkSpeedMultiplier = 1.0f;
// 缓存燃料组件
private CompRefuelableNutrition_WithKey compRefuelable;
private bool refuelableComponentCached = false;
// 获取燃料组件
private CompRefuelableNutrition_WithKey CompRefuelable
{
get
{
if (!refuelableComponentCached)
{
compRefuelable = parent.TryGetComp<CompRefuelableNutrition_WithKey>();
refuelableComponentCached = true;
}
return compRefuelable;
}
}
// 检查燃料是否充足
private bool HasSufficientFuel
{
get
{
if (!Props.requiresFuel)
return true;
if (CompRefuelable == null)
return false;
return CompRefuelable.Fuel >= Props.minFuelToOperate;
}
}
// 检查是否有足够的燃料用于标记
private bool HasSufficientFuelForMarking
{
get
{
if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
return true;
if (CompRefuelable == null)
return false;
return CompRefuelable.Fuel >= Props.fuelConsumptionPerMark;
}
}
// 消耗燃料(用于地形改变)
private bool ConsumeFuelIfNeeded()
{
if (!Props.requiresFuel || Props.fuelConsumptionPerChange <= 0)
return true;
if (CompRefuelable == null)
return false;
if (CompRefuelable.Fuel >= Props.fuelConsumptionPerChange)
{
CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerChange);
return true;
}
return false;
}
// 消耗标记燃料
private bool ConsumeMarkingFuelIfNeeded()
{
if (!Props.requiresFuel || Props.fuelConsumptionPerMark <= 0)
return true;
if (CompRefuelable == null)
return false;
if (CompRefuelable.Fuel >= Props.fuelConsumptionPerMark)
{
CompRefuelable.ConsumeFuel(Props.fuelConsumptionPerMark);
return true;
}
return false;
}
// 获取电源状态
private bool HasPower
{
get
{
if (!Props.requiresPower)
return true;
var compPower = parent.TryGetComp<CompPowerTrader>();
return compPower != null && compPower.PowerOn;
}
}
// 获取房间
private Room GetRoom()
{
var map = parent.Map;
if (map == null)
return null;
return parent.Position.GetRoom(map);
}
// 检查是否满足基本操作条件
private bool CanOperate()
{
// 检查是否有电
if (Props.requiresPower && !HasPower)
return false;
// 检查是否有足够的燃料
if (Props.requiresFuel && !HasSufficientFuel)
return false;
// 检查是否在房间内(如果需要)
if (Props.onlyInSameRoom)
{
var room = GetRoom();
if (room == null || !room.ProperRoom)
return false;
// 检查房间评分
if (room.GetStat(RoomStatDefOf.Impressiveness) < Props.minRoomScore)
return false;
}
return true;
}
// 检查是否可以执行标记操作
private bool CanMarkForRemoval()
{
if (!Props.enableAutoMarkForRemoval || !autoMarkForRemovalEnabled)
return false;
if (!CanOperate())
return false;
// 检查标记燃料
if (Props.requiresFuel && !HasSufficientFuelForMarking)
return false;
return true;
}
// 获取有效的工作单元格(地形改变)
private bool TryGetValidTargetCell(out IntVec3 result)
{
result = IntVec3.Invalid;
var map = parent.Map;
if (map == null)
return false;
// 获取搜索范围
var center = parent.Position;
int radius = Mathf.CeilToInt(Props.changeRadius);
// 获取房间(如果需要)
Room parentRoom = null;
if (Props.onlyInSameRoom)
{
parentRoom = GetRoom();
if (parentRoom == null)
return false;
}
// 收集所有候选单元格
List<IntVec3> candidateCells = new List<IntVec3>();
for (int x = -radius; x <= radius; x++)
{
for (int z = -radius; z <= radius; z++)
{
IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
if (!cell.InBounds(map))
continue;
// 检查距离
float distance = cell.DistanceTo(center);
if (distance > Props.changeRadius)
continue;
// 检查房间(如果需要)
if (Props.onlyInSameRoom)
{
var cellRoom = cell.GetRoom(map);
if (cellRoom == null || cellRoom != parentRoom)
continue;
}
// 获取当前地形
TerrainDef currentTerrain = map.terrainGrid.TerrainAt(cell);
// 如果已经是目标地形,跳过
if (currentTerrain == Props.targetTerrain)
continue;
// 检查是否在可接受地形列表中(如果有定义)
if (Props.acceptedTerrains != null && Props.acceptedTerrains.Count > 0)
{
if (!Props.acceptedTerrains.Contains(currentTerrain))
continue;
}
candidateCells.Add(cell);
}
}
if (candidateCells.Count == 0)
return false;
// 根据设置选择单元格
if (Props.prioritizeClosest)
{
// 找到最近的单元格
float closestDistance = float.MaxValue;
IntVec3 closestCell = IntVec3.Invalid;
foreach (var cell in candidateCells)
{
float distance = cell.DistanceTo(center);
if (distance < closestDistance)
{
closestDistance = distance;
closestCell = cell;
}
}
if (closestCell.IsValid)
{
result = closestCell;
return true;
}
}
else
{
// 随机选择一个单元格
result = candidateCells.RandomElement();
return true;
}
return false;
}
// 获取有效的标记拆除单元格
private bool TryGetValidMarkingCell(out IntVec3 result)
{
result = IntVec3.Invalid;
var map = parent.Map;
if (map == null)
return false;
// 获取搜索范围
var center = parent.Position;
int radius = Mathf.CeilToInt(Props.markRemovalRadius);
// 获取房间(如果需要)
Room parentRoom = null;
if (Props.onlyInSameRoom)
{
parentRoom = GetRoom();
if (parentRoom == null)
return false;
}
// 收集所有候选单元格
List<IntVec3> candidateCells = new List<IntVec3>();
for (int x = -radius; x <= radius; x++)
{
for (int z = -radius; z <= radius; z++)
{
IntVec3 cell = new IntVec3(center.x + x, 0, center.z + z);
if (!cell.InBounds(map))
continue;
// 检查距离
float distance = cell.DistanceTo(center);
if (distance > Props.markRemovalRadius)
continue;
// 检查房间(如果需要)
if (Props.onlyInSameRoom)
{
var cellRoom = cell.GetRoom(map);
if (cellRoom == null || cellRoom != parentRoom)
continue;
}
// 获取当前地形
TerrainDef currentTerrain = map.terrainGrid.TerrainAt(cell);
// 如果不是目标地形,跳过(只标记可以生成的地形)
if (currentTerrain != Props.targetTerrain)
continue;
// 检查是否已经标记了拆除
if (map.designationManager.DesignationAt(cell, DesignationDefOf.RemoveFloor) != null)
continue;
// 检查是否可以移除
if (!map.terrainGrid.CanRemoveTopLayerAt(cell))
continue;
// 检查是否有建筑阻挡
if (WorkGiver_ConstructRemoveFloor.AnyBuildingBlockingFloorRemoval(cell, map))
continue;
candidateCells.Add(cell);
}
}
if (candidateCells.Count == 0)
return false;
// 根据设置选择单元格
if (Props.prioritizeClosest)
{
// 找到最近的单元格
float closestDistance = float.MaxValue;
IntVec3 closestCell = IntVec3.Invalid;
foreach (var cell in candidateCells)
{
float distance = cell.DistanceTo(center);
if (distance < closestDistance)
{
closestDistance = distance;
closestCell = cell;
}
}
if (closestCell.IsValid)
{
result = closestCell;
return true;
}
}
else
{
// 随机选择一个单元格
result = candidateCells.RandomElement();
return true;
}
return false;
}
// 开始工作(地形改变)
private void StartWorking(IntVec3 targetCell)
{
this.targetCell = targetCell;
this.isWorking = true;
// 计算工作时间(基于距离)
float distance = targetCell.DistanceTo(parent.Position);
float workTimeFactor = 1f + (distance / Props.changeRadius) * 0.5f; // 距离越远,时间越长
int baseWorkTime = Mathf.RoundToInt(Props.baseChangeInterval * 0.1f); // 工作时间为间隔的10%
workTicksRemaining = Mathf.RoundToInt(baseWorkTime * workTimeFactor / currentWorkSpeedMultiplier);
// 播放声音
if (Props.workingSound != null)
{
Props.workingSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
}
// 开始标记工作
private void StartMarking(IntVec3 targetCell)
{
this.markingTargetCell = targetCell;
this.isMarking = true;
// 计算标记时间(基于距离)
float distance = targetCell.DistanceTo(parent.Position);
float workTimeFactor = 1f + (distance / Props.markRemovalRadius) * 0.5f;
int baseMarkTime = Mathf.RoundToInt(Props.markRemovalInterval * 0.05f); // 标记时间为间隔的5%
markingTicksRemaining = Mathf.RoundToInt(baseMarkTime * workTimeFactor / currentWorkSpeedMultiplier);
// 播放标记声音
if (Props.markSound != null)
{
Props.markSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
}
// 完成工作(地形改变)
private void CompleteWork()
{
var map = parent.Map;
if (map == null || !targetCell.IsValid || !targetCell.InBounds(map))
{
ResetWorkState();
return;
}
// 检查并消耗燃料
if (!ConsumeFuelIfNeeded())
{
Messages.Message("ARA_TerrainChanger.InsufficientFuel".Translate(),
new TargetInfo(targetCell, map), MessageTypeDefOf.NegativeEvent);
ResetWorkState();
return;
}
// 获取当前地形
TerrainDef currentTerrain = map.terrainGrid.TerrainAt(targetCell);
// 记录之前的地形
TerrainDef previousTerrain = currentTerrain;
// 改变地形
map.terrainGrid.SetTerrain(targetCell, Props.targetTerrain);
// 播放完成声音
if (Props.completionSound != null)
{
Props.completionSound.PlayOneShot(new TargetInfo(targetCell, map));
}
// 显示消息(可选)
if (Prefs.DevMode)
{
Log.Message($"[TerrainChanger] Changed terrain at {targetCell} from {previousTerrain?.defName ?? "null"} to {Props.targetTerrain.defName}");
}
ResetWorkState();
}
// 完成标记工作
private void CompleteMarking()
{
var map = parent.Map;
if (map == null || !markingTargetCell.IsValid || !markingTargetCell.InBounds(map))
{
ResetMarkingState();
return;
}
// 检查并消耗标记燃料
if (!ConsumeMarkingFuelIfNeeded())
{
Messages.Message("ARA_TerrainChanger.InsufficientFuelForMarking".Translate(),
new TargetInfo(markingTargetCell, map), MessageTypeDefOf.NegativeEvent);
ResetMarkingState();
return;
}
// 获取当前地形
TerrainDef currentTerrain = map.terrainGrid.TerrainAt(markingTargetCell);
// 确保是目标地形(安全检查)
if (currentTerrain != Props.targetTerrain)
{
ResetMarkingState();
return;
}
// 添加拆除标记
map.designationManager.AddDesignation(new Designation(markingTargetCell, DesignationDefOf.RemoveFloor));
// 播放完成声音
if (Props.markCompleteSound != null)
{
Props.markCompleteSound.PlayOneShot(new TargetInfo(markingTargetCell, map));
}
// 显示消息(可选)
if (Prefs.DevMode)
{
Log.Message($"[TerrainChanger] Marked terrain at {markingTargetCell} ({currentTerrain.defName}) for removal");
}
ResetMarkingState();
}
// 重置工作状态
private void ResetWorkState()
{
isWorking = false;
workTicksRemaining = 0;
targetCell = IntVec3.Invalid;
// 清理效果器
if (effecter != null)
{
effecter.Cleanup();
effecter = null;
}
}
// 重置标记状态
private void ResetMarkingState()
{
isMarking = false;
markingTicksRemaining = 0;
markingTargetCell = IntVec3.Invalid;
// 清理标记效果器
if (markingEffecter != null)
{
markingEffecter.Cleanup();
markingEffecter = null;
}
}
// 更新工作速度
private void UpdateWorkSpeed()
{
float multiplier = 1.0f;
if (Props.requiresPower && HasPower)
{
multiplier *= Props.poweredWorkSpeedMultiplier;
}
if (Props.requiresFuel && HasSufficientFuel)
{
// 燃料充足时可能有额外的速度加成
// 可以在这里添加燃料相关的速度加成
}
currentWorkSpeedMultiplier = multiplier;
}
// Tick更新
public override void CompTick()
{
base.CompTick();
// --- 处理地形改变 ---
if (isWorking)
{
workTicksRemaining--;
if (workTicksRemaining <= 0)
{
CompleteWork();
}
}
else if (CanOperate())
{
UpdateWorkSpeed();
// 等待下一次改变
if (ticksUntilNextChange <= 0)
{
// 尝试找到有效目标单元格
if (TryGetValidTargetCell(out IntVec3 target))
{
// 在开始工作前再次检查燃料
if (Props.requiresFuel && Props.fuelConsumptionPerChange > 0)
{
if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerChange)
{
// 燃料不足,重置计时器但跳过这次工作
ticksUntilNextChange = Mathf.RoundToInt(Props.baseChangeInterval / currentWorkSpeedMultiplier);
}
else
{
StartWorking(target);
}
}
else
{
StartWorking(target);
}
}
// 重置计时器,无论是否成功找到目标
ticksUntilNextChange = Mathf.RoundToInt(Props.baseChangeInterval / currentWorkSpeedMultiplier);
}
else
{
ticksUntilNextChange--;
}
}
// --- 处理自动标记拆除 ---
if (isMarking)
{
markingTicksRemaining--;
if (markingTicksRemaining <= 0)
{
CompleteMarking();
}
}
else if (CanMarkForRemoval())
{
// 等待下一次标记
if (ticksUntilNextMarkRemoval <= 0)
{
// 尝试找到有效标记单元格
if (TryGetValidMarkingCell(out IntVec3 target))
{
// 在开始标记前再次检查燃料
if (Props.requiresFuel && Props.fuelConsumptionPerMark > 0)
{
if (CompRefuelable == null || CompRefuelable.Fuel < Props.fuelConsumptionPerMark)
{
// 燃料不足,重置计时器但跳过这次标记
ticksUntilNextMarkRemoval = Mathf.RoundToInt(Props.markRemovalInterval / currentWorkSpeedMultiplier);
}
else
{
StartMarking(target);
}
}
else
{
StartMarking(target);
}
}
// 重置计时器,无论是否成功找到目标
ticksUntilNextMarkRemoval = Mathf.RoundToInt(Props.markRemovalInterval / currentWorkSpeedMultiplier);
}
else
{
ticksUntilNextMarkRemoval--;
}
}
}
// 防止长时间不工作
public override void CompTickRare()
{
base.CompTickRare();
if (!isWorking && ticksUntilNextChange > Props.baseChangeInterval * 10)
{
// 防止计时器溢出
ticksUntilNextChange = Props.baseChangeInterval;
}
if (!isMarking && ticksUntilNextMarkRemoval > Props.markRemovalInterval * 10)
{
// 防止标记计时器溢出
ticksUntilNextMarkRemoval = Props.markRemovalInterval;
}
}
// 保存/加载
public override void PostExposeData()
{
base.PostExposeData();
// 地形改变状态
Scribe_Values.Look(ref ticksUntilNextChange, "ticksUntilNextChange", Props.baseChangeInterval);
Scribe_Values.Look(ref isWorking, "isWorking", false);
Scribe_Values.Look(ref workTicksRemaining, "workTicksRemaining", 0);
Scribe_Values.Look(ref targetCell, "targetCell", IntVec3.Invalid);
// 标记拆除状态
Scribe_Values.Look(ref autoMarkForRemovalEnabled, "autoMarkForRemovalEnabled", true);
Scribe_Values.Look(ref ticksUntilNextMarkRemoval, "ticksUntilNextMarkRemoval", Props.markRemovalInterval);
Scribe_Values.Look(ref isMarking, "isMarking", false);
Scribe_Values.Look(ref markingTicksRemaining, "markingTicksRemaining", 0);
Scribe_Values.Look(ref markingTargetCell, "markingTargetCell", IntVec3.Invalid);
}
// 检查字符串
public override string CompInspectStringExtra()
{
var builder = new StringBuilder();
if (Props.requiresPower)
{
builder.AppendLine("ARA_TerrainChanger.Power".Translate(HasPower ? "On".Translate() : "Off".Translate()));
}
if (Props.requiresFuel)
{
if (CompRefuelable != null)
{
builder.AppendLine("ARA_TerrainChanger.Fuel".Translate(
CompRefuelable.Fuel.ToString("F1"),
CompRefuelable.TargetFuelLevel.ToString("F1")));
if (Props.fuelConsumptionPerChange > 0)
{
builder.AppendLine("ARA_TerrainChanger.FuelPerChange".Translate(
Props.fuelConsumptionPerChange.ToString("F1")));
}
if (Props.fuelConsumptionPerMark > 0)
{
builder.AppendLine("ARA_TerrainChanger.FuelPerMark".Translate(
Props.fuelConsumptionPerMark.ToString("F1")));
}
}
else
{
builder.AppendLine("ARA_TerrainChanger.NoFuelComponent".Translate());
}
}
if (isWorking)
{
float progressPercent = 1f - ((float)workTicksRemaining / (Props.baseChangeInterval * 0.1f));
builder.AppendLine("ARA_TerrainChanger.WorkingProgress".Translate(
progressPercent.ToStringPercent()));
builder.AppendLine("ARA_TerrainChanger.TargetCell".Translate(targetCell));
}
else
{
float daysUntilChange = ticksUntilNextChange / 60000f;
builder.AppendLine("ARA_TerrainChanger.NextChange".Translate(
daysUntilChange.ToString("F1")));
}
builder.AppendLine("ARA_TerrainChanger.TargetTerrain".Translate(
Props.targetTerrain.LabelCap));
builder.AppendLine("ARA_TerrainChanger.ChangeRadius".Translate(
Props.changeRadius.ToString("F1")));
return builder.ToString().TrimEndNewlines();
}
// 切换自动标记功能
private void ToggleAutoMarking()
{
autoMarkForRemovalEnabled = !autoMarkForRemovalEnabled;
if (autoMarkForRemovalEnabled)
{
Messages.Message("ARA_TerrainChanger.AutoMarkEnabled".Translate(),
parent, MessageTypeDefOf.PositiveEvent);
}
else
{
Messages.Message("ARA_TerrainChanger.AutoMarkDisabled".Translate(),
parent, MessageTypeDefOf.NeutralEvent);
}
}
// 获取Gizmos
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (var gizmo in base.CompGetGizmosExtra())
{
yield return gizmo;
}
// 只有在启用了自动标记功能时才显示切换按钮
if (Props.enableAutoMarkForRemoval && parent.Faction == Faction.OfPlayer)
{
yield return new Command_Toggle
{
defaultLabel = "ARA_TerrainChanger.ToggleAutoMark".Translate(),
defaultDesc = "ARA_TerrainChanger.ToggleAutoMarkDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Designators/RemoveFloor", false) ?? BaseContent.BadTex,
isActive = () => autoMarkForRemovalEnabled,
toggleAction = ToggleAutoMarking,
hotKey = KeyBindingDefOf.Misc4
};
}
}
// 建筑被销毁时清理
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
base.PostDestroy(mode, previousMap);
ResetWorkState();
ResetMarkingState();
}
// 建筑生成时初始化
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
refuelableComponentCached = false; // 重置缓存,重新获取组件
// 初始化自动标记状态
if (!respawningAfterLoad)
{
autoMarkForRemovalEnabled = Props.enableAutoMarkForRemoval;
ticksUntilNextMarkRemoval = Props.markRemovalInterval;
}
}
}
}

View File

@@ -15,29 +15,14 @@ namespace ArachnaeSwarm
}
public ThingDef turretDef;
public float angleOffset;
public bool autoAttack = true;
public bool defaultEnabled = true;
}
[StaticConstructorOnStartup]
public class HediffComp_TopTurret : HediffComp, IAttackTargetSearcher
{
// 添加 null 检查的属性
private HediffCompProperties_TopTurret Props
{
get
{
if (this.props == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: props is null");
return null;
}
return this.props as HediffCompProperties_TopTurret;
}
}
public Thing Thing
{
get
@@ -46,6 +31,14 @@ namespace ArachnaeSwarm
}
}
private HediffCompProperties_TopTurret Props
{
get
{
return (HediffCompProperties_TopTurret)this.props;
}
}
public Verb CurrentEffectiveVerb
{
get
@@ -74,11 +67,6 @@ namespace ArachnaeSwarm
{
get
{
if (this.gun == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: gun is null");
return null;
}
return this.gun.TryGetComp<CompEquippable>();
}
}
@@ -87,13 +75,7 @@ namespace ArachnaeSwarm
{
get
{
var comp = this.GunCompEq;
if (comp == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: GunCompEq is null");
return null;
}
return comp.PrimaryVerb;
return this.GunCompEq.PrimaryVerb;
}
}
@@ -105,10 +87,131 @@ namespace ArachnaeSwarm
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (!TurretEnabled)
{
ResetCurrentTarget();
return;
}
if (!this.CanShoot)
{
return;
}
if (this.currentTarget.IsValid)
{
this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
}
this.AttackVerb.VerbTick();
if (this.AttackVerb.state != VerbState.Bursting)
{
if (this.WarmingUp)
{
this.burstWarmupTicksLeft--;
if (this.burstWarmupTicksLeft == 0)
{
bool attackSuccess = this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
if (attackSuccess)
{
this.lastAttackTargetTick = Find.TickManager.TicksGame;
this.lastAttackedTarget = this.currentTarget;
}
return;
}
}
else
{
if (this.burstCooldownTicksLeft > 0)
{
this.burstCooldownTicksLeft--;
}
if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
{
// 自动寻找目标
this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
if (this.currentTarget.IsValid)
{
this.burstWarmupTicksLeft = 1;
return;
}
this.ResetCurrentTarget();
}
}
}
}
// 简化的Gizmos - 只有开关按钮
public override IEnumerable<Gizmo> CompGetGizmos()
{
// 只有 pawn 被选中且是玩家派系时才显示按钮
if (this.Pawn.Faction == Faction.OfPlayer && Find.Selector.IsSelected(this.Pawn))
{
yield return new Command_Toggle
{
defaultLabel = "CommandToggleTurret".Translate(),
defaultDesc = "CommandToggleTurretDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ToggleTurret"),
isActive = () => TurretEnabled,
toggleAction = () => TurretEnabled = !TurretEnabled,
hotKey = KeyBindingDefOf.Misc1
};
}
}
// 简化的提示信息
public override string CompTipStringExtra
{
get
{
string baseString = base.CompTipStringExtra;
string turretStatus = TurretEnabled ? "Turret: Active" : "Turret: Inactive";
string targetStatus = "Target: ";
if (this.currentTarget.IsValid)
{
targetStatus += $"{this.currentTarget.Thing?.LabelCap ?? this.currentTarget.Cell.ToString()}";
}
else
{
targetStatus += "None";
}
string result = turretStatus + "\n" + targetStatus;
return string.IsNullOrEmpty(baseString) ? result : baseString + "\n" + result;
}
}
// 炮塔启用状态
public bool TurretEnabled
{
get { return turretEnabled; }
set
{
turretEnabled = value;
if (!turretEnabled)
{
ResetCurrentTarget(); // 禁用时重置目标
}
}
}
private bool CanShoot
{
get
{
// 检查炮塔是否启用
if (!TurretEnabled)
return false;
Pawn pawn;
if ((pawn = (this.Pawn)) != null)
{
@@ -147,7 +250,7 @@ namespace ArachnaeSwarm
{
get
{
if (this.turretMat == null && this.Props?.turretDef?.graphicData != null)
if (this.turretMat == null)
{
this.turretMat = MaterialPool.MatFrom(this.Props.turretDef.graphicData.texPath);
}
@@ -159,71 +262,27 @@ namespace ArachnaeSwarm
{
get
{
return this.Props?.autoAttack ?? false;
return this.Props.autoAttack;
}
}
public override void CompPostMake()
{
base.CompPostMake();
// 添加 null 检查
if (this.Props == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: Props is null in CompPostMake");
return;
}
this.MakeGun();
// 设置默认启用状态
TurretEnabled = Props.defaultEnabled;
}
private void MakeGun()
{
// 添加详细的 null 检查
if (this.Props == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: Props is null in MakeGun");
return;
}
if (this.Props.turretDef == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: Props.turretDef is null");
return;
}
try
{
this.gun = ThingMaker.MakeThing(this.Props.turretDef, null);
if (this.gun == null)
{
ArachnaeLog.Debug($"HediffComp_TopTurret: Failed to create gun from turretDef '{this.Props.turretDef.defName}'");
return;
}
this.UpdateGunVerbs();
}
catch (Exception ex)
{
ArachnaeLog.Debug($"HediffComp_TopTurret: Exception in MakeGun: {ex}");
}
this.gun = ThingMaker.MakeThing(this.Props.turretDef, null);
this.UpdateGunVerbs();
}
private void UpdateGunVerbs()
{
if (this.gun == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: gun is null in UpdateGunVerbs");
return;
}
var comp = this.gun.TryGetComp<CompEquippable>();
if (comp == null)
{
ArachnaeLog.Debug("HediffComp_TopTurret: CompEquippable is null");
return;
}
List<Verb> allVerbs = comp.AllVerbs;
List<Verb> allVerbs = this.gun.TryGetComp<CompEquippable>().AllVerbs;
for (int i = 0; i < allVerbs.Count; i++)
{
Verb verb = allVerbs[i];
@@ -235,58 +294,6 @@ namespace ArachnaeSwarm
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
// 添加 null 检查
if (this.AttackVerb == null)
{
return;
}
if (!this.CanShoot)
{
return;
}
if (this.currentTarget.IsValid)
{
this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
}
this.AttackVerb.VerbTick();
if (this.AttackVerb.state != VerbState.Bursting)
{
if (this.WarmingUp)
{
this.burstWarmupTicksLeft--;
if (this.burstWarmupTicksLeft == 0)
{
this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
this.lastAttackTargetTick = Find.TickManager.TicksGame;
this.lastAttackedTarget = this.currentTarget;
return;
}
}
else
{
if (this.burstCooldownTicksLeft > 0)
{
this.burstCooldownTicksLeft--;
}
if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
{
this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
if (this.currentTarget.IsValid)
{
this.burstWarmupTicksLeft = 1;
return;
}
this.ResetCurrentTarget();
}
}
}
}
private void ResetCurrentTarget()
{
this.currentTarget = LocalTargetInfo.Invalid;
@@ -301,11 +308,13 @@ namespace ArachnaeSwarm
Scribe_TargetInfo.Look(ref this.currentTarget, "currentTarget");
Scribe_Deep.Look<Thing>(ref this.gun, "gun", Array.Empty<object>());
Scribe_Values.Look<bool>(ref this.fireAtWill, "fireAtWill", true, false);
// 保存启用状态
Scribe_Values.Look<bool>(ref this.turretEnabled, "turretEnabled", Props.defaultEnabled, false);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
if (this.gun == null)
{
ArachnaeLog.Debug("CompTurrentGun had null gun after loading. Recreating.");
this.MakeGun();
return;
}
@@ -315,24 +324,18 @@ namespace ArachnaeSwarm
private const int StartShootIntervalTicks = 10;
private static readonly CachedTexture ToggleTurretIcon = new CachedTexture("UI/Gizmos/ToggleTurret");
public Thing gun;
protected int burstCooldownTicksLeft;
protected int burstWarmupTicksLeft;
protected LocalTargetInfo currentTarget = LocalTargetInfo.Invalid;
private bool fireAtWill = true;
private LocalTargetInfo lastAttackedTarget = LocalTargetInfo.Invalid;
private int lastAttackTargetTick;
private float curRotation;
// 炮塔启用状态字段
private bool turretEnabled = true;
[Unsaved(false)]
public Material turretMat;
}

View File

@@ -112,7 +112,9 @@ namespace ArachnaeSwarm
int stripCount = (int)ChitinNeed.CurLevel;
if (stripCount < StripComp.Props.minStripAmount)
stripCount = StripComp.Props.minStripAmount;
stripCount = stripCount * 2;
// 获取甲壳物品定义
ThingDef carapaceDef = StripComp.CarapaceThingDef;
if (carapaceDef == null)

View File

@@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class Verb_ShootSelfUnderfoot : Verb_LaunchProjectile
{
// 重写ShotsPerBurst与Verb_Shoot相同
protected override int ShotsPerBurst => base.BurstShotCount;
// 重写WarmupComplete添加射击技能学习
public override void WarmupComplete()
{
base.WarmupComplete();
// 只有在目标是Pawn时才学习射击技能
if (currentTarget.Thing is Pawn targetPawn &&
!targetPawn.Downed &&
!targetPawn.IsColonyMech &&
CasterIsPawn &&
CasterPawn.skills != null)
{
float xp = targetPawn.HostileTo(caster) ? 170f : 20f;
float num2 = verbProps.AdjustedFullCycleTime(this, CasterPawn);
CasterPawn.skills.Learn(SkillDefOf.Shooting, xp * num2);
}
}
// 核心重写:将目标改为脚下
protected override bool TryCastShot()
{
// 保存原始目标
LocalTargetInfo originalTarget = currentTarget;
try
{
// 将目标改为施法者自己的位置
currentTarget = new LocalTargetInfo(caster.Position);
// 调用基类方法,但使用修改后的目标(脚下)
bool result = base.TryCastShot();
// 如果成功发射,记录射击次数
if (result && CasterIsPawn)
{
CasterPawn.records.Increment(RecordDefOf.ShotsFired);
}
return result;
}
finally
{
// 恢复原始目标(对于连续射击可能重要)
currentTarget = originalTarget;
}
}
// 重写CanHitTarget因为目标是脚下总是可以命中
public override bool CanHitTarget(LocalTargetInfo targ)
{
// 对于向脚下射击,我们总是允许(只要施法者存在)
if (caster == null || !caster.Spawned)
return false;
// 如果目标就是施法者自己,允许
if (targ == caster)
return true;
// 对于其他目标,使用默认逻辑
return base.CanHitTarget(targ);
}
// 重写CanHitTargetFrom对于脚下射击总是返回true
public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ)
{
// 如果目标是施法者自己(或脚下),总是可以命中
if (targ.Thing == caster || (targ.IsValid && targ.Cell == caster.Position))
return true;
return base.CanHitTargetFrom(root, targ);
}
// 重写TryFindShootLineFromTo对于脚下射击简化逻辑
public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine, bool ignoreRange = false)
{
// 如果目标是脚下,直接返回射击线
if (targ.IsValid && targ.Cell == caster.Position)
{
resultingLine = new ShootLine(root, targ.Cell);
return true;
}
// 否则使用基类逻辑
return base.TryFindShootLineFromTo(root, targ, out resultingLine, ignoreRange);
}
// 重写DrawHighlight简化高亮显示
public override void DrawHighlight(LocalTargetInfo target)
{
// 绘制标准射程环
verbProps.DrawRadiusRing(caster.Position, this);
// 如果目标是有效的,绘制目标高亮
if (target.IsValid)
{
GenDraw.DrawTargetHighlight(target);
// 绘制目标周围的场半径
DrawHighlightFieldRadiusAroundTarget(target);
}
}
// 辅助方法:绘制彩色目标高亮
private void GenDraw_DrawTargetHighlightWithColor(LocalTargetInfo target, Color color)
{
GenDraw.DrawTargetHighlight(target);
}
// 重写OnGUI显示自定义鼠标图标
public override void OnGUI(LocalTargetInfo target)
{
// 使用自定义图标或默认攻击图标
Texture2D icon;
if (!target.IsValid)
{
icon = TexCommand.CannotShoot;
}
else if (target.Cell == caster.Position)
{
// 可以使用自定义图标,这里使用攻击图标
icon = TexCommand.Attack;
}
else
{
icon = (UIIcon != BaseContent.BadTex) ? UIIcon : TexCommand.Attack;
}
GenUI.DrawMouseAttachment(icon);
}
// 重写ValidateTarget允许向自己脚下射击
public override bool ValidateTarget(LocalTargetInfo target, bool showMessages = true)
{
// 如果目标是脚下,总是允许
if (target.IsValid && target.Cell == caster.Position)
return true;
// 否则使用基类验证逻辑
return base.ValidateTarget(target, showMessages);
}
// 重写Available确保有抛射体并允许在近战状态下使用
public override bool Available()
{
// 首先调用基类检查
if (!base.Available())
return false;
// 检查是否有抛射体
if (Projectile == null)
return false;
// 特殊处理:允许在近战威胁下使用
if (CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
{
return true;
}
return true;
}
// 重写OrderForceTarget允许在近战距离内强制使用
public override void OrderForceTarget(LocalTargetInfo target)
{
// 如果是近战攻击,使用近战逻辑
if (verbProps.IsMeleeAttack)
{
Job job = JobMaker.MakeJob(JobDefOf.AttackMelee, target);
job.playerForced = true;
if (target.Thing is Pawn pawn)
{
job.killIncappedTarget = pawn.Downed;
}
CasterPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
return;
}
// 检查是否在近战范围内,但允许向脚下射击
float minRange = verbProps.EffectiveMinRange(target, CasterPawn);
if (CasterIsPawn &&
(float)CasterPawn.Position.DistanceToSquared(target.Cell) < minRange * minRange &&
CasterPawn.Position.AdjacentTo8WayOrInside(target.Cell))
{
// 如果是向脚下射击,允许
if (target.IsValid && target.Cell == CasterPawn.Position)
{
// 允许向脚下射击
}
else
{
Messages.Message("MessageCantShootInMelee".Translate(), CasterPawn, MessageTypeDefOf.RejectInput, historical: false);
return;
}
}
// 创建射击工作
Job job2 = JobMaker.MakeJob(verbProps.ai_IsWeapon ? JobDefOf.AttackStatic : JobDefOf.UseVerbOnThing);
job2.verbToUse = this;
job2.targetA = target;
job2.endIfCantShootInMelee = false; // 设置为false允许在近战中射击
CasterPawn.jobs.TryTakeOrderedJob(job2, JobTag.Misc);
}
// 重写TryStartCastOn允许在近战状态下开始射击
public override bool TryStartCastOn(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, bool canHitNonTargetPawns = true, bool preventFriendlyFire = false, bool nonInterruptingSelfCast = false)
{
// 调用基类方法,但设置一个标志表示这是向脚下射击
bool isShootingUnderfoot = castTarg.IsValid && castTarg.Cell == caster.Position;
// 如果是向脚下射击,临时修改一些属性以允许近战射击
if (isShootingUnderfoot && CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
{
// 临时忽略近战威胁检查
bool originalAIProjectileLaunchingIgnoresMeleeThreats = verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats;
verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = true;
try
{
return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
}
finally
{
// 恢复原始值
verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = originalAIProjectileLaunchingIgnoresMeleeThreats;
}
}
return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
}
// 添加一个方法,检查是否在近战状态下
public bool IsInMeleeCombat()
{
if (!CasterIsPawn)
return false;
return CasterPawn.mindState?.MeleeThreatStillThreat == true;
}
// 重写BurstingTick在近战状态下也继续射击
public override void BurstingTick()
{
base.BurstingTick();
// 在近战状态下也继续射击逻辑
if (IsInMeleeCombat() && state == VerbState.Bursting)
{
// 可以在这里添加近战状态下的特殊效果
}
}
// 添加自定义属性,用于控制是否总是向脚下发射
private bool alwaysShootUnderfoot = true;
public bool AlwaysShootUnderfoot
{
get => alwaysShootUnderfoot;
set => alwaysShootUnderfoot = value;
}
// 添加一个方法,允许临时关闭向脚下射击
public void SetShootUnderfoot(bool shootUnderfoot)
{
alwaysShootUnderfoot = shootUnderfoot;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB