三大系统
This commit is contained in:
Binary file not shown.
@@ -328,8 +328,8 @@
|
||||
<!-- 蜜罐种 -->
|
||||
<HediffDef>
|
||||
<defName>ARA_Myrmecocystus_Production_InsectJelly</defName>
|
||||
<label>产出虫蜜</label>
|
||||
<description>这只阿拉克涅蜜罐种正在产出虫蜜,以滋养虫群。一只蜜罐种每天产出15份阿拉克涅虫蜜。</description>
|
||||
<label>虫蜜腔室</label>
|
||||
<description>这只阿拉克涅蜜罐种正在产出虫蜜,以滋养虫群。</description>
|
||||
<descriptionHyperlinks>
|
||||
<ThingDef>ARA_InsectJelly</ThingDef>
|
||||
<HediffDef>ARA_Myrmecocystus_Production_Medicine</HediffDef>
|
||||
@@ -368,61 +368,14 @@
|
||||
</drawData>
|
||||
</li>
|
||||
</renderNodeProperties>
|
||||
<!-- <stages>
|
||||
<stages>
|
||||
<li>
|
||||
<becomeVisible>ture</becomeVisible>
|
||||
<enablesNeeds>
|
||||
<li>ARA_HoneyProduction</li>
|
||||
</enablesNeeds>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>1.01</minSeverity>
|
||||
<becomeVisible>false</becomeVisible>
|
||||
</li>
|
||||
</stages> -->
|
||||
</stages>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.MoharHediffs.HediffCompProperties_Spawner">
|
||||
<!--
|
||||
==================================================
|
||||
基础设置 (Basic Settings)
|
||||
==================================================
|
||||
-->
|
||||
<!-- [DEBUG] 如果为true,则为此组件启用详细的调试日志记录。 -->
|
||||
<debug>true</debug>
|
||||
<!-- 要生成的物品的ThingDef。 -->
|
||||
<thingToSpawn>ARA_InsectJelly</thingToSpawn>
|
||||
<!-- 每次生成的基础物品数量。 -->
|
||||
<spawnCount>15</spawnCount>
|
||||
<!--
|
||||
==================================================
|
||||
生成周期 (Spawning Interval)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 下一次生成事件发生前的最少天数。 -->
|
||||
<minDaysB4Next>1</minDaysB4Next>
|
||||
<!-- 下一次生成事件发生前的最大天数。 -->
|
||||
<maxDaysB4Next>1</maxDaysB4Next>
|
||||
<randomGrace>0</randomGrace>
|
||||
<!--
|
||||
==================================================
|
||||
与年龄相关的调整 (Age-Related Adjustments)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 如果为true,生成数量将根据宿主的年龄进行调整。 -->
|
||||
<ageWeightedQuantity>false</ageWeightedQuantity>
|
||||
<!-- 如果为true且ageWeightedQuantity为true,则随着宿主年龄增长,生成数量变多。 -->
|
||||
<olderBiggerQuantity>true</olderBiggerQuantity>
|
||||
<!-- 如果为true且ageWeightedQuantity为true,则随年龄增长的数量缩放将是指数性的而非线性的。 -->
|
||||
<exponentialQuantity>true</exponentialQuantity>
|
||||
<!-- 指数级数量缩放的最大乘数,以防止出现荒谬的数字。 -->
|
||||
<exponentialRatioLimit>20</exponentialRatioLimit>
|
||||
<!--
|
||||
==================================================
|
||||
生成条件 (Spawning Conditions)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 如果为true,当宿主Pawn饥饿时,生成将暂停。 -->
|
||||
<hungerRelative>true</hungerRelative>
|
||||
<!-- 如果为true,当宿主Pawn受伤时,生成将暂停。 -->
|
||||
<healthRelative>false</healthRelative>
|
||||
</li>
|
||||
<li Class="HediffCompProperties_GiveAbility">
|
||||
<abilityDefs>
|
||||
<li>ARA_Myrmecocystus_Production_Medicine</li>
|
||||
@@ -1203,51 +1156,6 @@
|
||||
</li>
|
||||
</stages>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.MoharHediffs.HediffCompProperties_Spawner">
|
||||
<!--
|
||||
==================================================
|
||||
基础设置 (Basic Settings)
|
||||
==================================================
|
||||
-->
|
||||
<!-- [DEBUG] 如果为true,则为此组件启用详细的调试日志记录。 -->
|
||||
<debug>true</debug>
|
||||
<!-- 要生成的物品的ThingDef。 -->
|
||||
<thingToSpawn>ARA_Carapace</thingToSpawn>
|
||||
<!-- 每次生成的基础物品数量。 -->
|
||||
<spawnCount>15</spawnCount>
|
||||
<!--
|
||||
==================================================
|
||||
生成周期 (Spawning Interval)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 下一次生成事件发生前的最少天数。 -->
|
||||
<minDaysB4Next>1</minDaysB4Next>
|
||||
<!-- 下一次生成事件发生前的最大天数。 -->
|
||||
<maxDaysB4Next>1</maxDaysB4Next>
|
||||
<randomGrace>0</randomGrace>
|
||||
<!--
|
||||
==================================================
|
||||
与年龄相关的调整 (Age-Related Adjustments)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 如果为true,生成数量将根据宿主的年龄进行调整。 -->
|
||||
<ageWeightedQuantity>false</ageWeightedQuantity>
|
||||
<!-- 如果为true且ageWeightedQuantity为true,则随着宿主年龄增长,生成数量变多。 -->
|
||||
<olderBiggerQuantity>true</olderBiggerQuantity>
|
||||
<!-- 如果为true且ageWeightedQuantity为true,则随年龄增长的数量缩放将是指数性的而非线性的。 -->
|
||||
<exponentialQuantity>true</exponentialQuantity>
|
||||
<!-- 指数级数量缩放的最大乘数,以防止出现荒谬的数字。 -->
|
||||
<exponentialRatioLimit>20</exponentialRatioLimit>
|
||||
<!--
|
||||
==================================================
|
||||
生成条件 (Spawning Conditions)
|
||||
==================================================
|
||||
-->
|
||||
<!-- 如果为true,当宿主Pawn饥饿时,生成将暂停。 -->
|
||||
<hungerRelative>true</hungerRelative>
|
||||
<!-- 如果为true,当宿主Pawn受伤时,生成将暂停。 -->
|
||||
<healthRelative>false</healthRelative>
|
||||
</li>
|
||||
<li Class="HediffCompProperties_GiveAbility">
|
||||
<abilityDefs>
|
||||
<li>ARA_ShieldHead_Protector</li>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<li>Outdoors</li>
|
||||
</disablesNeeds>
|
||||
<enablesNeeds>
|
||||
<li>ARA_ChitinArmor</li>
|
||||
<li>Indoors</li>
|
||||
</enablesNeeds>
|
||||
</li>
|
||||
@@ -54,6 +55,9 @@
|
||||
<li>DrugDesire</li>
|
||||
<li>RoomSize</li>
|
||||
</disablesNeeds>
|
||||
<enablesNeeds>
|
||||
<li>ARA_ChitinArmor</li>
|
||||
</enablesNeeds>
|
||||
</li>
|
||||
</stages>
|
||||
<comps>
|
||||
@@ -95,6 +99,9 @@
|
||||
<li>DrugDesire</li>
|
||||
<li>RoomSize</li>
|
||||
</disablesNeeds>
|
||||
<enablesNeeds>
|
||||
<li>ARA_ChitinArmor</li>
|
||||
</enablesNeeds>
|
||||
</li>
|
||||
</stages>
|
||||
</HediffDef>
|
||||
@@ -301,4 +308,76 @@
|
||||
</li>
|
||||
</comps>
|
||||
</HediffDef>
|
||||
|
||||
<HediffDef>
|
||||
<defName>ARA_ChitinArmor</defName>
|
||||
<label>甲壳护甲</label>
|
||||
<description>阿拉克涅虫族身上的甲壳,可以根据厚度为阿拉克涅虫族提供保护。</description>
|
||||
<hediffClass>HediffWithComps</hediffClass>
|
||||
<stages>
|
||||
<li>
|
||||
<minSeverity>0</minSeverity>
|
||||
<label>极薄</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.95</IncomingDamageFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>0.99</minSeverity>
|
||||
<label>薄</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.9</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0.9</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>1.99</minSeverity>
|
||||
<label>适中</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.85</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0.75</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>2.99</minSeverity>
|
||||
<label>较厚</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.7</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0.5</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>3.99</minSeverity>
|
||||
<label>厚</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.5</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0.25</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>4.99</minSeverity>
|
||||
<label>极厚</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.35</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>5.99</minSeverity>
|
||||
<label>固若磐石</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.25</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>6.99</minSeverity>
|
||||
<label>坚不可摧</label>
|
||||
<statFactors>
|
||||
<IncomingDamageFactor>0.1</IncomingDamageFactor>
|
||||
<StaggerDurationFactor>0</StaggerDurationFactor>
|
||||
</statFactors>
|
||||
</li>
|
||||
</stages>
|
||||
</HediffDef>
|
||||
</Defs>
|
||||
@@ -38,4 +38,61 @@
|
||||
<makeTargetPrisoner>false</makeTargetPrisoner>
|
||||
<casualInterruptible>true</casualInterruptible>
|
||||
</JobDef>
|
||||
<JobDef>
|
||||
<defName>ARA_OperateEquipmentIncubator</defName>
|
||||
<driverClass>ArachnaeSwarm.JobDriver_OperateEquipmentIncubator</driverClass>
|
||||
<reportString>激活阿拉克涅茧。</reportString>
|
||||
<playerInterruptible>true</playerInterruptible>
|
||||
<alwaysShowWeapon>false</alwaysShowWeapon>
|
||||
<suspendable>true</suspendable>
|
||||
<makeTargetPrisoner>false</makeTargetPrisoner>
|
||||
<casualInterruptible>true</casualInterruptible>
|
||||
</JobDef>
|
||||
|
||||
<!-- 喂养工作 -->
|
||||
<JobDef>
|
||||
<defName>ARA_FeedWithHoney</defName>
|
||||
<driverClass>ArachnaeSwarm.JobDriver_FeedWithHoney</driverClass>
|
||||
<reportString>正在喂养TargetA。</reportString>
|
||||
<alwaysShowWeapon>false</alwaysShowWeapon>
|
||||
<suspendable>true</suspendable>
|
||||
<playerInterruptible>true</playerInterruptible>
|
||||
<!-- <checkOverrideOnDamage></checkOverrideOnDamage> -->
|
||||
<casualInterruptible>true</casualInterruptible>
|
||||
<!-- <canBeForced>false</canBeForced> -->
|
||||
<!-- <joySkill>Social</joySkill>
|
||||
<joyXpPerTick>0.0005</joyXpPerTick> -->
|
||||
</JobDef>
|
||||
<JobDef>
|
||||
<defName>ARA_ExtractHoney</defName>
|
||||
<driverClass>ArachnaeSwarm.JobDriver_ExtractHoney</driverClass>
|
||||
<reportString>正在挤出虫蜜。</reportString>
|
||||
<alwaysShowWeapon>false</alwaysShowWeapon>
|
||||
<suspendable>true</suspendable>
|
||||
<playerInterruptible>true</playerInterruptible>
|
||||
<!-- <checkOverrideOnDamage>Minor</checkOverrideOnDamage> -->
|
||||
<casualInterruptible>true</casualInterruptible>
|
||||
<!-- <canBeForced>false</canBeForced> -->
|
||||
</JobDef>
|
||||
<!-- 甲壳剥离工作 -->
|
||||
<JobDef>
|
||||
<defName>ARA_StripChitin</defName>
|
||||
<driverClass>ArachnaeSwarm.JobDriver_StripChitin</driverClass>
|
||||
<reportString>正在剥离甲壳</reportString>
|
||||
<playerInterruptible>true</playerInterruptible>
|
||||
<alwaysShowWeapon>false</alwaysShowWeapon>
|
||||
<suspendable>true</suspendable>
|
||||
<!-- <checkOverrideOnDamage>CheckJobOverrideOnDamageMode.Always</checkOverrideOnDamage> -->
|
||||
</JobDef>
|
||||
<JobDef>
|
||||
<defName>ARA_SwarmMaintain</defName>
|
||||
<driverClass>ArachnaeSwarm.JobDriver_SwarmMaintain</driverClass>
|
||||
<reportString>正在维护TargetA。</reportString>
|
||||
<playerInterruptible>true</playerInterruptible>
|
||||
<!-- <checkOverrideOnDamage>CheckJobOverrideOnDamageMode.Always</checkOverrideOnDamage> -->
|
||||
<alwaysShowWeapon>false</alwaysShowWeapon>
|
||||
<suspendable>true</suspendable>
|
||||
<casualInterruptible>true</casualInterruptible>
|
||||
<makeTargetPrisoner>false</makeTargetPrisoner>
|
||||
</JobDef>
|
||||
</Defs>
|
||||
@@ -4,16 +4,57 @@
|
||||
<defName>ARA_HoneyProduction</defName>
|
||||
<needClass>ArachnaeSwarm.Need_HoneyProduction</needClass>
|
||||
<label>蜜罐</label>
|
||||
<description>代表这个生物储存阿拉克涅虫蜜原浆的多少。当其他虫族饥饿时,会尝试直接从有蜜罐腔的生物身上获取虫蜜,如果蜜罐满溢,则生物会尝试将其提取出来。</description>
|
||||
<description>代表这个生物储存阿拉克涅虫蜜原浆的多少。当其他虫族饥饿时,有蜜罐腔的生物会尝试喂养它们;如果蜜罐满溢,则生物会尝试将其提取出来。</description>
|
||||
<listPriority>800</listPriority>
|
||||
<major>true</major>
|
||||
<onlyIfCausedByHediff>true</onlyIfCausedByHediff>
|
||||
<hediffRequiredAny>
|
||||
<li>Wula_Synth</li>
|
||||
<li>ARA_Myrmecocystus_Production_InsectJelly</li>
|
||||
</hediffRequiredAny>
|
||||
<showForCaravanMembers>true</showForCaravanMembers>
|
||||
<developmentalStageFilter>Baby, Child, Adult</developmentalStageFilter>
|
||||
<showUnitTicks>true</showUnitTicks>
|
||||
<freezeWhileSleeping>false</freezeWhileSleeping>
|
||||
|
||||
<modExtensions>
|
||||
<li Class="ArachnaeSwarm.HoneyProductionExtension">
|
||||
<!-- 基础转化率:食物流失的60%转化为蜜罐 -->
|
||||
<baseConversionRate>0.8</baseConversionRate>
|
||||
|
||||
<!-- 生产速率乘数(更快生产) -->
|
||||
<productionSpeedFactor>1</productionSpeedFactor>
|
||||
</li>
|
||||
</modExtensions>
|
||||
</NeedDef>
|
||||
<NeedDef>
|
||||
<defName>ARA_ChitinArmor</defName>
|
||||
<needClass>ArachnaeSwarm.Need_ChitinArmor</needClass>
|
||||
<label>甲壳</label>
|
||||
<description>代表这个生物身上的阿拉克涅甲壳的厚度,越厚的甲壳越能为虫族带来强大的防御力。虫族也可以将其从身上剥离下来,以生产甲壳素。</description>
|
||||
<listPriority>800</listPriority>
|
||||
<major>true</major>
|
||||
<onlyIfCausedByHediff>true</onlyIfCausedByHediff>
|
||||
<hediffRequiredAny>
|
||||
<li>ARA_HiveMindMaster</li>
|
||||
<li>ARA_HiveMindDrone</li>
|
||||
<li>ARA_NonPlayer_HiveMindDroneHediff</li>
|
||||
</hediffRequiredAny>
|
||||
<showForCaravanMembers>true</showForCaravanMembers>
|
||||
<developmentalStageFilter>Baby, Child, Adult</developmentalStageFilter>
|
||||
<showUnitTicks>true</showUnitTicks>
|
||||
<freezeWhileSleeping>false</freezeWhileSleeping>
|
||||
|
||||
<modExtensions>
|
||||
<li Class="ArachnaeSwarm.NeedDefExtension_ChitinLevels">
|
||||
<hediff>ARA_ChitinArmor</hediff>
|
||||
<severityRange>
|
||||
<min>0.0</min>
|
||||
<max>10.0</max>
|
||||
</severityRange>
|
||||
<removeOnDeath>true</removeOnDeath>
|
||||
<baseGrowthRate>0.1</baseGrowthRate>
|
||||
<squareCoefficient>0.1</squareCoefficient>
|
||||
</li>
|
||||
</modExtensions>
|
||||
</NeedDef>
|
||||
</Defs>
|
||||
@@ -210,8 +210,6 @@
|
||||
</backstoryFiltersOverride>
|
||||
<abilities>
|
||||
<li>ARA_AcidSprayBurst</li>
|
||||
<li>ARA_RaceBaseSwarmProduceOff</li>
|
||||
<li>ARA_RaceBaseSwarmProduceOn</li>
|
||||
</abilities>
|
||||
<apparelTags>
|
||||
</apparelTags>
|
||||
@@ -256,10 +254,6 @@
|
||||
<apparelTags>
|
||||
</apparelTags>
|
||||
<apparelMoney>0</apparelMoney>
|
||||
<abilities>
|
||||
<li>ARA_RaceBaseSwarmProduceOff</li>
|
||||
<li>ARA_RaceBaseSwarmProduceOn</li>
|
||||
</abilities>
|
||||
</PawnKindDef>
|
||||
<PawnKindDef ParentName="ArachnaeNodeABasePawnKind">
|
||||
<defName>ArachnaeNode_Race_Facehugger</defName>
|
||||
@@ -498,50 +492,6 @@
|
||||
</li>
|
||||
</lifeStages>
|
||||
</PawnKindDef>
|
||||
<PawnKindDef ParentName="ARA_InsectKindBase">
|
||||
<defName>ArachnaeBase_Race_HardJaw</defName>
|
||||
<label>阿拉克涅坚颚种</label>
|
||||
<race>ArachnaeBase_Race_HardJaw</race>
|
||||
<lifeStages>
|
||||
<li>
|
||||
<bodyGraphicData>
|
||||
<texPath>ArachnaeSwarm/Things/ARA_Scavenger/HardJaw/Naked_Thin</texPath>
|
||||
<drawSize>1</drawSize>
|
||||
<color>(156,148,125)</color>
|
||||
<shadowData>
|
||||
<volume>(0.4, 0.5, 0.37)</volume>
|
||||
<offset>(0,0,-0.15)</offset>
|
||||
</shadowData>
|
||||
</bodyGraphicData>
|
||||
<dessicatedBodyGraphicData>
|
||||
<texPath>Things/Pawn/Animal/Spelopede/Dessicated_Spelopede</texPath>
|
||||
<drawSize>1</drawSize>
|
||||
</dessicatedBodyGraphicData>
|
||||
</li>
|
||||
</lifeStages>
|
||||
</PawnKindDef>
|
||||
<PawnKindDef ParentName="ARA_InsectKindBase">
|
||||
<defName>ArachnaeBase_Race_Maid</defName>
|
||||
<label>阿拉克涅家政种</label>
|
||||
<race>ArachnaeBase_Race_Maid</race>
|
||||
<lifeStages>
|
||||
<li>
|
||||
<bodyGraphicData>
|
||||
<texPath>ArachnaeSwarm/Things/ARA_Scavenger/Maid/Naked_Thin</texPath>
|
||||
<drawSize>1</drawSize>
|
||||
<color>(156,148,125)</color>
|
||||
<shadowData>
|
||||
<volume>(0.4, 0.5, 0.37)</volume>
|
||||
<offset>(0,0,-0.15)</offset>
|
||||
</shadowData>
|
||||
</bodyGraphicData>
|
||||
<dessicatedBodyGraphicData>
|
||||
<texPath>Things/Pawn/Animal/Spelopede/Dessicated_Spelopede</texPath>
|
||||
<drawSize>1</drawSize>
|
||||
</dessicatedBodyGraphicData>
|
||||
</li>
|
||||
</lifeStages>
|
||||
</PawnKindDef>
|
||||
<PawnKindDef Name="ArachnaeBase_Race_Acidcut" ParentName="ARA_InsectKindBase">
|
||||
<defName>ArachnaeBase_Race_Acidcut</defName>
|
||||
<label>阿拉克涅酸噬种</label>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<workerClass>ArachnaeSwarm.RoomRoleWorker_Incubator</workerClass>
|
||||
<relatedStats>
|
||||
<li>Space</li>
|
||||
<li>ARA_IncubatorRateFactor</li>
|
||||
<li>ARA_IncubatorQualityFactor</li>
|
||||
</relatedStats>
|
||||
</RoomRoleDef>
|
||||
</Defs>
|
||||
|
||||
@@ -775,11 +775,6 @@
|
||||
</race>
|
||||
|
||||
<comps>
|
||||
<!-- <li Class="ArachnaeSwarm.CompProperties_MilkableArachnae">
|
||||
<milkDef>ARA_InsectJelly</milkDef>
|
||||
<milkIntervalDays>1</milkIntervalDays>
|
||||
<milkAmount>10</milkAmount>
|
||||
</li> -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_NodeSwarmLifetime">
|
||||
<immuteHediff>ARA_Cycle_Suppression_Hediff</immuteHediff>
|
||||
<lifespanHediff>ARA_LifespanHediff</lifespanHediff>
|
||||
@@ -937,7 +932,7 @@
|
||||
<allowDuplicates>false</allowDuplicates>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_AutoMechCarrier">
|
||||
<freeProduction>false</freeProduction>
|
||||
<freeProduction>true</freeProduction>
|
||||
<disableHediff>ARA_RaceBaseSwarmProduceSwitchHediff</disableHediff>
|
||||
<fixedIngredient>ARA_InsectJelly</fixedIngredient>
|
||||
<maxIngredientCount>1</maxIngredientCount>
|
||||
@@ -1063,24 +1058,6 @@
|
||||
<addChance>1.0</addChance>
|
||||
<allowDuplicates>false</allowDuplicates>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_AutoMechCarrier">
|
||||
<freeProduction>true</freeProduction>
|
||||
<disableHediff>ARA_RaceBaseSwarmProduceSwitchHediff</disableHediff>
|
||||
<fixedIngredient>ARA_InsectJelly</fixedIngredient>
|
||||
<maxIngredientCount>1</maxIngredientCount>
|
||||
<startingIngredientCount>1</startingIngredientCount>
|
||||
<costPerPawn>999</costPerPawn>
|
||||
<cooldownTicks>9999</cooldownTicks>
|
||||
<productionQueue>
|
||||
<li>
|
||||
<!-- <pawnKind>ArachnaeBase_Race_Slavey</pawnKind> -->
|
||||
<pawnKind>ArachnaeBase_Race_Maid</pawnKind>
|
||||
<count>3</count>
|
||||
<cooldownTicks>1000</cooldownTicks>
|
||||
</li>
|
||||
</productionQueue>
|
||||
<spawnEffecter>CocoonDestroyed</spawnEffecter>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_NodeSwarmLifetime">
|
||||
<immuteHediff>ARA_Cycle_Suppression_Hediff</immuteHediff>
|
||||
<lifespanHediff>ARA_LifespanHediff</lifespanHediff>
|
||||
@@ -1419,24 +1396,6 @@
|
||||
<addChance>1.0</addChance>
|
||||
<allowDuplicates>false</allowDuplicates>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_AutoMechCarrier">
|
||||
<freeProduction>true</freeProduction>
|
||||
<disableHediff>ARA_RaceBaseSwarmProduceSwitchHediff</disableHediff>
|
||||
<fixedIngredient>ARA_InsectJelly</fixedIngredient>
|
||||
<maxIngredientCount>1</maxIngredientCount>
|
||||
<startingIngredientCount>1</startingIngredientCount>
|
||||
<costPerPawn>999</costPerPawn>
|
||||
<cooldownTicks>9999</cooldownTicks>
|
||||
<productionQueue>
|
||||
<li>
|
||||
<!-- <pawnKind>ArachnaeBase_Race_Slavey</pawnKind> -->
|
||||
<pawnKind>ArachnaeBase_Race_Maid</pawnKind>
|
||||
<count>5</count>
|
||||
<cooldownTicks>1000</cooldownTicks>
|
||||
</li>
|
||||
</productionQueue>
|
||||
<spawnEffecter>CocoonDestroyed</spawnEffecter>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_NodeSwarmLifetime">
|
||||
<immuteHediff>ARA_Cycle_Suppression_Hediff</immuteHediff>
|
||||
<lifespanHediff>ARA_LifespanHediff</lifespanHediff>
|
||||
|
||||
@@ -169,6 +169,14 @@
|
||||
<addChance>1.0</addChance>
|
||||
<allowDuplicates>false</allowDuplicates>
|
||||
</li>
|
||||
<!-- 甲壳剥离组件 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_ChitinStripping">
|
||||
<canStripChitin>true</canStripChitin>
|
||||
<stripThreshold>0.8</stripThreshold>
|
||||
<minStripAmount>1</minStripAmount>
|
||||
<stripInterval>3000</stripInterval>
|
||||
<carapaceThingDef>ARA_Carapace</carapaceThingDef>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
<AlienRace.ThingDef_AlienRace Name="ARA_QueenBase" ParentName="ARA_PawnBase">
|
||||
@@ -420,8 +428,7 @@
|
||||
<!-- 可以驯服的宠物,主要是防止小虫由别人驯服 -->
|
||||
<petList>
|
||||
<li>ArachnaeBase_Race_Scavenger</li>
|
||||
<li>ArachnaeBase_Race_HardJaw</li>
|
||||
<li>ArachnaeBase_Race_Maid</li>
|
||||
<li>ArachnaeBase_Race_Larva</li>
|
||||
</petList>
|
||||
<onlyTameRaceRestrictedPets>true</onlyTameRaceRestrictedPets>
|
||||
<!-- 可以穿戴的衣服 -->
|
||||
|
||||
@@ -73,9 +73,7 @@
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
|
||||
<cocoonDefs>
|
||||
<li>ARA_Cocoon_Weapon</li>
|
||||
<li>ARA_Cocoon_Weapon_From_Death</li>
|
||||
<li>ARA_BioforgeIncubator_Thing</li>
|
||||
<li>ARA_Equipment_Ootheca</li>
|
||||
</cocoonDefs>
|
||||
</li>
|
||||
</comps>
|
||||
|
||||
@@ -495,9 +495,16 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>3</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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>
|
||||
@@ -558,13 +565,20 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps Inherit="False">
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_ReportWorkSpeed">
|
||||
<workSpeedStat>ResearchSpeedFactor</workSpeedStat>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>4</spawnRadius>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
@@ -627,6 +641,17 @@
|
||||
</researchPrerequisites>
|
||||
<designationCategory>ARA_Buildings</designationCategory>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Flickable">
|
||||
<commandTexture>UI/Commands/Vent</commandTexture>
|
||||
@@ -638,10 +663,6 @@
|
||||
<!-- 这是设备的热交换功率。数值越大,制冷/制热速度越快。-->
|
||||
<energyPerSecond>25</energyPerSecond>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>3</spawnRadius>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
@@ -691,9 +712,16 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>3</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<glowRadius>3</glowRadius>
|
||||
@@ -759,9 +787,16 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>2</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<glowRadius>3</glowRadius>
|
||||
@@ -833,9 +868,16 @@
|
||||
<li>PlaceWorker_GlowRadius</li>
|
||||
</placeWorkers>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>2</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<glowRadius>7</glowRadius>
|
||||
@@ -998,9 +1040,16 @@
|
||||
</relatedTerrain>
|
||||
</building>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>5</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<glowRadius>4</glowRadius>
|
||||
@@ -1047,9 +1096,16 @@
|
||||
</building>
|
||||
<!-- 不可建造,只能通过变形生成 -->
|
||||
<comps Inherit="False">
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>3</spawnRadius>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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_Morphable">
|
||||
<!-- 休息速度增益,例如1.0代表200%的速度 -->
|
||||
|
||||
@@ -33,19 +33,6 @@
|
||||
<ARA_Carapace>20</ARA_Carapace>
|
||||
<ARA_InsectJelly>3</ARA_InsectJelly>
|
||||
</costList>
|
||||
<comps>
|
||||
<li Class="CompProperties_Transporter">
|
||||
<massCapacity>300</massCapacity>
|
||||
<restEffectiveness>0.8</restEffectiveness>
|
||||
<canChangeAssignedThingsAfterStarting>true</canChangeAssignedThingsAfterStarting>
|
||||
<!-- <max1PerGroup>true</max1PerGroup> -->
|
||||
</li>
|
||||
<li Class="CompProperties_Launchable_TransportPod">
|
||||
<skyfallerLeaving>ARA_DropPodLeaving</skyfallerLeaving>
|
||||
<requiresFuelingPort>false</requiresFuelingPort>
|
||||
<fixedLaunchDistanceMax>53</fixedLaunchDistanceMax> <!-- 80% of full transport pod range -->
|
||||
</li>
|
||||
</comps>
|
||||
<researchPrerequisites>
|
||||
<li>ARA_Technology_8POD</li>
|
||||
</researchPrerequisites>
|
||||
@@ -58,6 +45,30 @@
|
||||
<uiIconScale>0.65</uiIconScale>
|
||||
<dropPodFaller>ARA_DropPodIncoming</dropPodFaller>
|
||||
<dropPodActive>ARA_ActiveDropPod</dropPodActive>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Transporter">
|
||||
<massCapacity>300</massCapacity>
|
||||
<restEffectiveness>0.8</restEffectiveness>
|
||||
<canChangeAssignedThingsAfterStarting>true</canChangeAssignedThingsAfterStarting>
|
||||
<!-- <max1PerGroup>true</max1PerGroup> -->
|
||||
</li>
|
||||
<li Class="CompProperties_Launchable_TransportPod">
|
||||
<skyfallerLeaving>ARA_DropPodLeaving</skyfallerLeaving>
|
||||
<requiresFuelingPort>false</requiresFuelingPort>
|
||||
<fixedLaunchDistanceMax>53</fixedLaunchDistanceMax> <!-- 80% of full transport pod range -->
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="ActiveDropPod">
|
||||
|
||||
@@ -36,6 +36,17 @@
|
||||
</costList>
|
||||
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<overlightRadius>7.0</overlightRadius>
|
||||
<glowRadius>14</glowRadius>
|
||||
@@ -162,6 +173,18 @@
|
||||
<constructionSkillPrerequisite>4</constructionSkillPrerequisite>
|
||||
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
|
||||
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
|
||||
<warningThreshold>0.2</warningThreshold>
|
||||
<assignJobCheckInterval>1800</assignJobCheckInterval>
|
||||
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
|
||||
<allowedRaces>
|
||||
<li>ArachnaeNode_Race_WeaponSmith</li>
|
||||
</allowedRaces>
|
||||
</li>
|
||||
|
||||
<!-- 1. 作为消费者,自己也需要燃料 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
|
||||
<fuelCapacity>5.0</fuelCapacity>
|
||||
|
||||
@@ -98,11 +98,37 @@
|
||||
<!-- <claimable>false</claimable> -->
|
||||
<deconstructible>false</deconstructible>
|
||||
<repairable>false</repairable>
|
||||
<isTargetable>false</isTargetable>
|
||||
<!-- <isTargetable>false</isTargetable> -->
|
||||
<!-- <expandHomeArea>false</expandHomeArea> -->
|
||||
<workTableRoomRole>ARA_Incubator_Room</workTableRoomRole>
|
||||
</building>
|
||||
|
||||
<!-- 添加 ModExtension 配置 -->
|
||||
<modExtensions>
|
||||
<li Class="ArachnaeSwarm.OothecaIncubatorExtension">
|
||||
<!-- 营养液检测半径 -->
|
||||
<nutrientSolutionRadius>5</nutrientSolutionRadius>
|
||||
<!-- 其他卵距离检测半径 -->
|
||||
<nearbyOothecaRadius>5</nearbyOothecaRadius>
|
||||
<!-- 是否检查同房间内的其他卵 -->
|
||||
<checkSameRoomForOotheca>false</checkSameRoomForOotheca>
|
||||
<!-- 营养液加成比例 -->
|
||||
<!-- <nutrientSolutionBonusPerTile>0.015</nutrientSolutionBonusPerTile> -->
|
||||
<!-- 附近其他卵的惩罚比例 -->
|
||||
<!-- <nearbyOothecaPenaltyPerUnit>0.08</nearbyOothecaPenaltyPerUnit> -->
|
||||
<!-- 幼虫搜索半径 -->
|
||||
<!-- <larvaSearchRadius>30</larvaSearchRadius> -->
|
||||
<!-- 是否需要在孵化间内才能正常工作 -->
|
||||
<!-- <requiresIncubatorRoom>true</requiresIncubatorRoom> -->
|
||||
<!-- 不在孵化间内的速度惩罚 -->
|
||||
<!-- <speedPenaltyOutsideIncubator>0.7</speedPenaltyOutsideIncubator> -->
|
||||
<!-- 质量因子房间检查 -->
|
||||
<!-- <useRoomQualityFactor>true</useRoomQualityFactor> -->
|
||||
<!-- 建筑血量影响质量 -->
|
||||
<!-- <healthAffectsQuality>true</healthAffectsQuality> -->
|
||||
</li>
|
||||
</modExtensions>
|
||||
|
||||
<!-- ITab配置 -->
|
||||
<inspectorTabs>
|
||||
<li>ArachnaeSwarm.ITab_Ootheca_Incubation</li>
|
||||
@@ -112,6 +138,17 @@
|
||||
<li>ArachnaeSwarm.PlaceWorker_CustomRadius</li>
|
||||
</placeWorkers>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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_CustomRadius">
|
||||
<radius>5</radius> <!-- 半径大小 -->
|
||||
<color>(0.5, 1, 1)</color> <!-- 绿色圆圈 -->
|
||||
@@ -144,7 +181,7 @@
|
||||
<pawnKind>ArachnaeNode_Race_Fighter</pawnKind>
|
||||
<daysRequired>2</daysRequired>
|
||||
<buttonIconPath>UI/Buttons/IncubateUnitA</buttonIconPath>
|
||||
<!-- <requiredResearch>ARA_Technology_1KYC</requiredResearch> -->
|
||||
<requiredResearch>ARA_Technology_1KYC</requiredResearch>
|
||||
</li>
|
||||
<li>
|
||||
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
|
||||
@@ -203,4 +240,125 @@
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="BuildingNaturalBase">
|
||||
<defName>ARA_Equipment_Ootheca</defName>
|
||||
<label>阿拉克涅茧</label>
|
||||
<description>一个脆弱、易燃、黏滑的囊状物,是阿拉克涅女皇种所诞之卵,内含哺育一只新督虫所需的营养和遗传物质。</description>
|
||||
<statBases>
|
||||
<MarketValue>1000</MarketValue>
|
||||
</statBases>
|
||||
<thingClass>ArachnaeSwarm.Building_EquipmentOotheca</thingClass>
|
||||
<category>Building</category>
|
||||
<size>(1,1)</size>
|
||||
<designationCategory>ARA_Buildings</designationCategory>
|
||||
<graphicData>
|
||||
<texPath>ArachnaeSwarm/Building/ARA_Cocoon</texPath>
|
||||
<graphicClass>Graphic_Single</graphicClass>
|
||||
<drawSize>(1.1,1.1)</drawSize>
|
||||
<shadowData>
|
||||
<volume>(0.7, 0.4, 0.7)</volume>
|
||||
<offset>(0,0,-0.1)</offset>
|
||||
</shadowData>
|
||||
</graphicData>
|
||||
<altitudeLayer>Building</altitudeLayer>
|
||||
<passability>PassThroughOnly</passability>
|
||||
<fillPercent>0.3</fillPercent>
|
||||
<rotatable>false</rotatable>
|
||||
<tickerType>Normal</tickerType>
|
||||
<generateCommonality>0</generateCommonality>
|
||||
<tradeability>None</tradeability>
|
||||
<thingSetMakerTags Inherit="False" />
|
||||
<terrainAffordanceNeeded>ARA_Incubator_Nutrient_Solution</terrainAffordanceNeeded>
|
||||
<!-- 交互设置 -->
|
||||
<interactionCellOffset>(0, 0, 1)</interactionCellOffset>
|
||||
<hasInteractionCell>true</hasInteractionCell>
|
||||
<statBases>
|
||||
<Mass>10</Mass>
|
||||
<MaxHitPoints>150</MaxHitPoints>
|
||||
<Flammability>1</Flammability>
|
||||
<Beauty>-6</Beauty>
|
||||
</statBases>
|
||||
<building>
|
||||
<isInert>true</isInert>
|
||||
<!-- <claimable>false</claimable> -->
|
||||
<deconstructible>false</deconstructible>
|
||||
<repairable>false</repairable>
|
||||
<!-- <isTargetable>false</isTargetable> -->
|
||||
<!-- <expandHomeArea>false</expandHomeArea> -->
|
||||
<workTableRoomRole>ARA_Incubator_Room</workTableRoomRole>
|
||||
</building>
|
||||
|
||||
<!-- 添加 ModExtension 配置 -->
|
||||
<modExtensions>
|
||||
<li Class="ArachnaeSwarm.OothecaIncubatorExtension">
|
||||
<!-- 营养液检测半径 -->
|
||||
<nutrientSolutionRadius>3</nutrientSolutionRadius>
|
||||
<!-- 其他卵距离检测半径 -->
|
||||
<nearbyOothecaRadius>3</nearbyOothecaRadius>
|
||||
<!-- 是否检查同房间内的其他卵 -->
|
||||
<checkSameRoomForOotheca>false</checkSameRoomForOotheca>
|
||||
<!-- 营养液加成比例 -->
|
||||
<nutrientSolutionBonusPerTile>0.03</nutrientSolutionBonusPerTile>
|
||||
<!-- 附近其他卵的惩罚比例 -->
|
||||
<!-- <nearbyOothecaPenaltyPerUnit>0.08</nearbyOothecaPenaltyPerUnit> -->
|
||||
<!-- 幼虫搜索半径 -->
|
||||
<!-- <larvaSearchRadius>30</larvaSearchRadius> -->
|
||||
<!-- 是否需要在孵化间内才能正常工作 -->
|
||||
<!-- <requiresIncubatorRoom>true</requiresIncubatorRoom> -->
|
||||
<!-- 不在孵化间内的速度惩罚 -->
|
||||
<!-- <speedPenaltyOutsideIncubator>0.7</speedPenaltyOutsideIncubator> -->
|
||||
<!-- 质量因子房间检查 -->
|
||||
<!-- <useRoomQualityFactor>true</useRoomQualityFactor> -->
|
||||
<!-- 建筑血量影响质量 -->
|
||||
<!-- <healthAffectsQuality>true</healthAffectsQuality> -->
|
||||
</li>
|
||||
</modExtensions>
|
||||
|
||||
<!-- ITab配置 -->
|
||||
<inspectorTabs>
|
||||
<li>ArachnaeSwarm.ITab_EquipmentOotheca_Incubation</li>
|
||||
</inspectorTabs>
|
||||
|
||||
<placeWorkers>
|
||||
<li>ArachnaeSwarm.PlaceWorker_CustomRadius</li>
|
||||
</placeWorkers>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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_CustomRadius">
|
||||
<radius>3</radius> <!-- 半径大小 -->
|
||||
<color>(0.5, 1, 1)</color> <!-- 绿色圆圈 -->
|
||||
<radiusOffset>0</radiusOffset> <!-- 半径偏移 -->
|
||||
<showInGUI>true</showInGUI>
|
||||
<label>吸收半径</label>
|
||||
<description>这个卵在孵化过程中的吸收半径,确保这些地格中铺满阿拉克涅营养液,并且没有其他的卵,以获得最佳的孵化速度和孵化质量。</description>
|
||||
<defaultVisible>false</defaultVisible>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_EquipmentIncubatorData">
|
||||
<!-- autoScanThingDefs默认为true,会自动扫描所有ThingDef -->
|
||||
</li>
|
||||
<li Class="CompProperties_SpawnEffecterOnDestroy">
|
||||
<effect>CocoonDestroyed</effect>
|
||||
</li>
|
||||
<li Class="CompProperties_Glower">
|
||||
<glowRadius>6</glowRadius>
|
||||
<glowColor>(113,141,117,0)</glowColor>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_TemperatureRuinableDamage">
|
||||
<minSafeTemperature>-10</minSafeTemperature>
|
||||
<maxSafeTemperature>20</maxSafeTemperature>
|
||||
<damagePerTick>0.015</damagePerTick>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
</Defs>
|
||||
@@ -63,6 +63,18 @@
|
||||
<constructionSkillPrerequisite>4</constructionSkillPrerequisite>
|
||||
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</maintenanceDecayPerDay>
|
||||
<damagePerSecondWhenEmpty>2</damagePerSecondWhenEmpty>
|
||||
<warningThreshold>0.2</warningThreshold>
|
||||
<assignJobCheckInterval>1800</assignJobCheckInterval>
|
||||
<maintenanceThresholdForJob>0.5</maintenanceThresholdForJob>
|
||||
<allowedRaces>
|
||||
<li>ArachnaeNode_Race_WeaponSmith</li>
|
||||
</allowedRaces>
|
||||
</li>
|
||||
|
||||
<!-- 标准的 CompRefuelable -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_ProductStorage">
|
||||
<fuelLabel>精华素</fuelLabel>
|
||||
|
||||
@@ -288,6 +288,17 @@
|
||||
<tickerType>Normal</tickerType>
|
||||
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Forbiddable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
|
||||
<saveKeysPrefix>nutrition</saveKeysPrefix>
|
||||
@@ -305,10 +316,6 @@
|
||||
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_ForceTargetable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>6</spawnRadius>
|
||||
</li>
|
||||
<li Class="CompProperties_AffectedByFacilities">
|
||||
<linkableFacilities>
|
||||
<li>ARA_NutrientNetworkTower</li>
|
||||
@@ -430,6 +437,17 @@
|
||||
<tickerType>Normal</tickerType>
|
||||
<terrainAffordanceNeeded>Heavy</terrainAffordanceNeeded>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Forbiddable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
|
||||
<saveKeysPrefix>nutrition</saveKeysPrefix>
|
||||
@@ -446,10 +464,6 @@
|
||||
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||
</li>
|
||||
<li Class="ArachnaeSwarm.CompProperties_ForceTargetable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>6</spawnRadius>
|
||||
</li>
|
||||
<li Class="CompProperties_AffectedByFacilities">
|
||||
<linkableFacilities>
|
||||
<li>ARA_NutrientNetworkTower</li>
|
||||
@@ -595,6 +609,17 @@
|
||||
</statBases>
|
||||
<tickerType>Normal</tickerType>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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_RefuelableNutrition_WithKey">
|
||||
<saveKeysPrefix>nutrition</saveKeysPrefix>
|
||||
<fuelCapacity>50.0</fuelCapacity>
|
||||
@@ -611,10 +636,6 @@
|
||||
<li Class="CompProperties_Forbiddable" />
|
||||
<li Class="CompProperties_Breakdownable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_ForceTargetable" />
|
||||
<li Class="ArachnaeSwarm.CompProperties_DelayedTerrainSpawn">
|
||||
<terrainToSpawn>ARA_InsectCreep</terrainToSpawn>
|
||||
<spawnRadius>8</spawnRadius>
|
||||
</li>
|
||||
<li Class="CompProperties_AffectedByFacilities">
|
||||
<linkableFacilities>
|
||||
<li>ARA_NutrientNetworkTower</li>
|
||||
|
||||
@@ -39,6 +39,17 @@
|
||||
<ARA_Carapace>200</ARA_Carapace>
|
||||
</costList>
|
||||
<comps>
|
||||
<li Class="ArachnaeSwarm.CompProperties_SwarmMaintenance">
|
||||
<maxMaintenance>100</maxMaintenance>
|
||||
<maintenanceDecayPerDay>15</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="CompProperties_Glower">
|
||||
<overlightRadius>7.0</overlightRadius>
|
||||
<glowRadius>14</glowRadius>
|
||||
|
||||
@@ -896,6 +896,35 @@
|
||||
<insertTag>Humanlike_PreMain</insertTag>
|
||||
</li>
|
||||
|
||||
<!-- 蜜罐特殊思考:喂食 -->
|
||||
<li Class="ThinkNode_ConditionalPawnKind">
|
||||
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
|
||||
<subNodes>
|
||||
<li Class="ArachnaeSwarm.ThinkNode_JobGiver_FeedWithHoney" />
|
||||
</subNodes>
|
||||
</li>
|
||||
<li Class="ThinkNode_ConditionalPawnKind">
|
||||
<pawnKind>ArachnaeNode_Race_Myrmecocystus</pawnKind>
|
||||
<subNodes>
|
||||
<li Class="ArachnaeSwarm.ThinkNode_JobGiver_ExtractHoney" />
|
||||
</subNodes>
|
||||
</li>
|
||||
|
||||
<li Class="ThinkNode_ConditionalHasHediff">
|
||||
<hediff>ARA_HiveMindMaster</hediff>
|
||||
<severityRange>0~5</severityRange>
|
||||
<subNodes>
|
||||
<li Class="ArachnaeSwarm.ThinkNode_JobGiver_StripChitin" />
|
||||
</subNodes>
|
||||
</li>
|
||||
<li Class="ThinkNode_ConditionalHasHediff">
|
||||
<hediff>ARA_HiveMindDrone</hediff>
|
||||
<severityRange>0~5</severityRange>
|
||||
<subNodes>
|
||||
<li Class="ArachnaeSwarm.ThinkNode_JobGiver_StripChitin" />
|
||||
</subNodes>
|
||||
</li>
|
||||
|
||||
<!-- Main colonist behavior core -->
|
||||
<li Class="ThinkNode_ConditionalColonist">
|
||||
<subNodes>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<Target>目标</Target>
|
||||
<SpeedMultiplier>速度乘数</SpeedMultiplier>
|
||||
<QualityMultiplier>质量乘数</QualityMultiplier>
|
||||
<LarvaIsOperating>幼虫种种进入中</LarvaIsOperating>
|
||||
<LarvaIsOperating>幼虫种进入中</LarvaIsOperating>
|
||||
<SRemaining>剩余秒数</SRemaining>
|
||||
<LarvaIsOnTheWay>幼虫种正在路上</LarvaIsOnTheWay>
|
||||
<TimeRemaining>剩余时间</TimeRemaining>
|
||||
@@ -97,4 +97,76 @@
|
||||
|
||||
<!-- Research Related -->
|
||||
<ResearchRequired>需要研究</ResearchRequired>
|
||||
|
||||
|
||||
<!-- 孵化系统翻译 -->
|
||||
<ARA_OothecaIncubator.SpeedFactors>速度因子</ARA_OothecaIncubator.SpeedFactors>
|
||||
<ARA_OothecaIncubator.InIncubatorRoom>✓ 位于孵化间内</ARA_OothecaIncubator.InIncubatorRoom>
|
||||
<ARA_OothecaIncubator.NotInIncubatorRoom>✗ 不在孵化间内</ARA_OothecaIncubator.NotInIncubatorRoom>
|
||||
<ARA_OothecaIncubator.NutrientSolutions>营养液: {0} (+{1}%)</ARA_OothecaIncubator.NutrientSolutions>
|
||||
<ARA_OothecaIncubator.NoNutrientSolutionsNearby>无附近营养液</ARA_OothecaIncubator.NoNutrientSolutionsNearby>
|
||||
<ARA_OothecaIncubator.NutrientDetectionRadius>营养液检测半径: {0}格</ARA_OothecaIncubator.NutrientDetectionRadius>
|
||||
<ARA_OothecaIncubator.TotalSpeedMultiplier>总速度乘数: {0}</ARA_OothecaIncubator.TotalSpeedMultiplier>
|
||||
|
||||
<ARA_OothecaIncubator.QualityFactors>质量因子</ARA_OothecaIncubator.QualityFactors>
|
||||
<ARA_OothecaIncubator.BuildingHealth>建筑健康度: {0}</ARA_OothecaIncubator.BuildingHealth>
|
||||
<ARA_OothecaIncubator.RoomFactorNormal>房间因子: 正常</ARA_OothecaIncubator.RoomFactorNormal>
|
||||
<ARA_OothecaIncubator.RoomFactorModified>房间因子: </ARA_OothecaIncubator.RoomFactorModified>
|
||||
<ARA_OothecaIncubator.NearbyOothecas>附近卵: {0} (-{1}%)</ARA_OothecaIncubator.NearbyOothecas>
|
||||
<ARA_OothecaIncubator.NoNearbyOothecas>无附近卵</ARA_OothecaIncubator.NoNearbyOothecas>
|
||||
<ARA_OothecaIncubator.OothecaDetectionRadius>卵检测半径: {0}格</ARA_OothecaIncubator.OothecaDetectionRadius>
|
||||
<ARA_OothecaIncubator.TotalQualityMultiplier>总质量乘数: {0}</ARA_OothecaIncubator.TotalQualityMultiplier>
|
||||
|
||||
<ARA_OothecaIncubator.CallLarvaTitle>呼叫幼虫</ARA_OothecaIncubator.CallLarvaTitle>
|
||||
<ARA_OothecaIncubator.LarvaWillCome>幼虫将前往卵荚进行孵化</ARA_OothecaIncubator.LarvaWillCome>
|
||||
<ARA_OothecaIncubator.LarvaSearchRadius>幼虫搜索半径: {0}格</ARA_OothecaIncubator.LarvaSearchRadius>
|
||||
|
||||
<ARA_OothecaIncubator.AlreadyIncubating>已经在孵化中</ARA_OothecaIncubator.AlreadyIncubating>
|
||||
<ARA_OothecaIncubator.CancelFirst>请先取消当前孵化</ARA_OothecaIncubator.CancelFirst>
|
||||
<ARA_OothecaIncubator.LarvaAlreadyOnWay>幼虫已在途中</ARA_OothecaIncubator.LarvaAlreadyOnWay>
|
||||
<ARA_OothecaIncubator.NoLarvaeFound>未找到可用幼虫</ARA_OothecaIncubator.NoLarvaeFound>
|
||||
<ARA_OothecaIncubator.LarvaMustBeRace>必须是幼虫种</ARA_OothecaIncubator.LarvaMustBeRace>
|
||||
<ARA_OothecaIncubator.LarvaCalled>幼虫已呼叫</ARA_OothecaIncubator.LarvaCalled>
|
||||
<ARA_OothecaIncubator.ArriveShortly>即将到达</ARA_OothecaIncubator.ArriveShortly>
|
||||
<ARA_OothecaIncubator.LarvaArrived>幼虫已到达</ARA_OothecaIncubator.LarvaArrived>
|
||||
<ARA_OothecaIncubator.ActivatingOotheca>正在激活卵荚</ARA_OothecaIncubator.ActivatingOotheca>
|
||||
<ARA_OothecaIncubator.IncubationStarted>开始孵化</ARA_OothecaIncubator.IncubationStarted>
|
||||
<ARA_OothecaIncubator.ProcessWillComplete>过程将在</ARA_OothecaIncubator.ProcessWillComplete>
|
||||
<ARA_OothecaIncubator.DaysBaseTime>天内完成(基础时间)</ARA_OothecaIncubator.DaysBaseTime>
|
||||
<ARA_OothecaIncubator.IncubationCancelled>孵化已取消</ARA_OothecaIncubator.IncubationCancelled>
|
||||
<ARA_OothecaIncubator.ContentsLost>内容物已丢失</ARA_OothecaIncubator.ContentsLost>
|
||||
<ARA_OothecaIncubator.IncubationComplete>孵化完成</ARA_OothecaIncubator.IncubationComplete>
|
||||
<ARA_OothecaIncubator.HasEmergedWith>已出现,质量为</ARA_OothecaIncubator.HasEmergedWith>
|
||||
<ARA_OothecaIncubator.QualityExcellent>优秀</ARA_OothecaIncubator.QualityExcellent>
|
||||
<ARA_OothecaIncubator.QualityGood>良好</ARA_OothecaIncubator.QualityGood>
|
||||
<ARA_OothecaIncubator.QualityAverage>一般</ARA_OothecaIncubator.QualityAverage>
|
||||
<ARA_OothecaIncubator.QualityPoor>较差</ARA_OothecaIncubator.QualityPoor>
|
||||
<ARA_OothecaIncubator.QualityVeryPoor>很差</ARA_OothecaIncubator.QualityVeryPoor>
|
||||
<ARA_OothecaIncubator.Quality>质量</ARA_OothecaIncubator.Quality>
|
||||
|
||||
<ARA_OothecaIncubator.Incubating>正在孵化</ARA_OothecaIncubator.Incubating>
|
||||
<ARA_OothecaIncubator.Progress>进度</ARA_OothecaIncubator.Progress>
|
||||
<ARA_OothecaIncubator.TimeRemaining>剩余时间</ARA_OothecaIncubator.TimeRemaining>
|
||||
<ARA_OothecaIncubator.Days>天</ARA_OothecaIncubator.Days>
|
||||
<ARA_OothecaIncubator.Hours>小时</ARA_OothecaIncubator.Hours>
|
||||
<ARA_OothecaIncubator.Speed>速度</ARA_OothecaIncubator.Speed>
|
||||
<ARA_OothecaIncubator.Quality>质量</ARA_OothecaIncubator.Quality>
|
||||
<ARA_OothecaIncubator.LarvaOperating>幼虫正在操作</ARA_OothecaIncubator.LarvaOperating>
|
||||
<ARA_OothecaIncubator.SRemaining>秒剩余</ARA_OothecaIncubator.SRemaining>
|
||||
<ARA_OothecaIncubator.LarvaOnWay>幼虫在途中</ARA_OothecaIncubator.LarvaOnWay>
|
||||
<ARA_OothecaIncubator.Target>目标</ARA_OothecaIncubator.Target>
|
||||
<ARA_OothecaIncubator.SpeedMultiplier>速度乘数</ARA_OothecaIncubator.SpeedMultiplier>
|
||||
<ARA_OothecaIncubator.QualityMultiplier>质量乘数</ARA_OothecaIncubator.QualityMultiplier>
|
||||
|
||||
<ARA_OothecaIncubator.CallLarva>呼叫幼虫</ARA_OothecaIncubator.CallLarva>
|
||||
<ARA_OothecaIncubator.CancelIncubation>取消孵化</ARA_OothecaIncubator.CancelIncubation>
|
||||
<ARA_OothecaIncubator.CancelIncubationDesc>取消当前孵化过程,卵荚内容物将丢失</ARA_OothecaIncubator.CancelIncubationDesc>
|
||||
|
||||
<ARA_OothecaIncubator.IncubateLabel>孵化: {0}</ARA_OothecaIncubator.IncubateLabel>
|
||||
<ARA_OothecaIncubator.ButtonDesc>选择要孵化的生物类型。幼虫将前来激活卵荚。</ARA_OothecaIncubator.ButtonDesc>
|
||||
<ARA_OothecaIncubator.ButtonLabel>当前选择: {0}</ARA_OothecaIncubator.ButtonLabel>
|
||||
<ARA_OothecaIncubator.IncubationTime>孵化时间: {0}天</ARA_OothecaIncubator.IncubationTime>
|
||||
<ARA_OothecaIncubator.MenuTitle>选择孵化目标</ARA_OothecaIncubator.MenuTitle>
|
||||
<ARA_OothecaIncubator.ResearchRequired>需要研究: </ARA_OothecaIncubator.ResearchRequired>
|
||||
<ARA_OothecaIncubator.TargetSwitched>孵化目标已切换为: {0}</ARA_OothecaIncubator.TargetSwitched>
|
||||
</LanguageData>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LanguageData>
|
||||
<!-- 装备孵化系统翻译 -->
|
||||
<ARA_EquipmentIncubator.SpeedFactors>速度因子</ARA_EquipmentIncubator.SpeedFactors>
|
||||
<ARA_EquipmentIncubator.InIncubatorRoom>✓ 位于孵化间内</ARA_EquipmentIncubator.InIncubatorRoom>
|
||||
<ARA_EquipmentIncubator.NotInIncubatorRoom>✗ 不在孵化间内</ARA_EquipmentIncubator.NotInIncubatorRoom>
|
||||
<ARA_EquipmentIncubator.NutrientSolutions>营养液: {0} (+{1}%)</ARA_EquipmentIncubator.NutrientSolutions>
|
||||
<ARA_EquipmentIncubator.NoNutrientSolutionsNearby>无附近营养液</ARA_EquipmentIncubator.NoNutrientSolutionsNearby>
|
||||
<ARA_EquipmentIncubator.NutrientDetectionRadius>营养液检测半径: {0}格</ARA_EquipmentIncubator.NutrientDetectionRadius>
|
||||
<ARA_EquipmentIncubator.TotalSpeedMultiplier>总速度乘数: {0}</ARA_EquipmentIncubator.TotalSpeedMultiplier>
|
||||
|
||||
<ARA_EquipmentIncubator.QualityFactors>质量因子</ARA_EquipmentIncubator.QualityFactors>
|
||||
<ARA_EquipmentIncubator.BuildingHealth>建筑健康度: {0}</ARA_EquipmentIncubator.BuildingHealth>
|
||||
<ARA_EquipmentIncubator.RoomFactorNormal>房间因子: 正常</ARA_EquipmentIncubator.RoomFactorNormal>
|
||||
<ARA_EquipmentIncubator.RoomFactorModified>房间因子: </ARA_EquipmentIncubator.RoomFactorModified>
|
||||
<ARA_EquipmentIncubator.NearbyOothecas>附近卵: {0} (-{1}%)</ARA_EquipmentIncubator.NearbyOothecas>
|
||||
<ARA_EquipmentIncubator.NoNearbyOothecas>无附近卵</ARA_EquipmentIncubator.NoNearbyOothecas>
|
||||
<ARA_EquipmentIncubator.OothecaDetectionRadius>卵检测半径: {0}格</ARA_EquipmentIncubator.OothecaDetectionRadius>
|
||||
<ARA_EquipmentIncubator.TotalQualityMultiplier>总质量乘数: {0}</ARA_EquipmentIncubator.TotalQualityMultiplier>
|
||||
|
||||
<ARA_EquipmentIncubator.CallLarvaTitle>呼叫幼虫</ARA_EquipmentIncubator.CallLarvaTitle>
|
||||
<ARA_EquipmentIncubator.LarvaWillCome>幼虫将前往卵荚生产装备</ARA_EquipmentIncubator.LarvaWillCome>
|
||||
<ARA_EquipmentIncubator.LarvaSearchRadius>幼虫搜索半径: {0}格</ARA_EquipmentIncubator.LarvaSearchRadius>
|
||||
|
||||
<ARA_EquipmentIncubator.AlreadyIncubating>已经在生产中</ARA_EquipmentIncubator.AlreadyIncubating>
|
||||
<ARA_EquipmentIncubator.CancelFirst>请先取消当前生产</ARA_EquipmentIncubator.CancelFirst>
|
||||
<ARA_EquipmentIncubator.LarvaAlreadyOnWay>幼虫已在途中</ARA_EquipmentIncubator.LarvaAlreadyOnWay>
|
||||
<ARA_EquipmentIncubator.NoLarvaeFound>未找到可用幼虫</ARA_EquipmentIncubator.NoLarvaeFound>
|
||||
<ARA_EquipmentIncubator.LarvaMustBeRace>幼虫必须是ArachnaeBase_Race_Larva种族</ARA_EquipmentIncubator.LarvaMustBeRace>
|
||||
<ARA_EquipmentIncubator.LarvaCalled>幼虫已呼叫</ARA_EquipmentIncubator.LarvaCalled>
|
||||
<ARA_EquipmentIncubator.ArriveShortly>即将到达</ARA_EquipmentIncubator.ArriveShortly>
|
||||
<ARA_EquipmentIncubator.LarvaArrived>幼虫已到达</ARA_EquipmentIncubator.LarvaArrived>
|
||||
<ARA_EquipmentIncubator.ActivatingOotheca>正在激活装备卵荚</ARA_EquipmentIncubator.ActivatingOotheca>
|
||||
<ARA_EquipmentIncubator.IncubationStarted>开始生产</ARA_EquipmentIncubator.IncubationStarted>
|
||||
<ARA_EquipmentIncubator.ProcessWillComplete>过程将在</ARA_EquipmentIncubator.ProcessWillComplete>
|
||||
<ARA_EquipmentIncubator.DaysBaseTime>天内完成(基础时间)</ARA_EquipmentIncubator.DaysBaseTime>
|
||||
<ARA_EquipmentIncubator.IncubationCancelled>生产已取消</ARA_EquipmentIncubator.IncubationCancelled>
|
||||
<ARA_EquipmentIncubator.ContentsLost>内容物已丢失</ARA_EquipmentIncubator.ContentsLost>
|
||||
<ARA_EquipmentIncubator.IncubationComplete>生产完成</ARA_EquipmentIncubator.IncubationComplete>
|
||||
<ARA_EquipmentIncubator.HasEmergedWith>已生产出,质量为</ARA_EquipmentIncubator.HasEmergedWith>
|
||||
<ARA_EquipmentIncubator.QualityExcellent>传奇</ARA_EquipmentIncubator.QualityExcellent>
|
||||
<ARA_EquipmentIncubator.QualityGood>杰作</ARA_EquipmentIncubator.QualityGood>
|
||||
<ARA_EquipmentIncubator.QualityAverage>精良</ARA_EquipmentIncubator.QualityAverage>
|
||||
<ARA_EquipmentIncubator.QualityPoor>良好</ARA_EquipmentIncubator.QualityPoor>
|
||||
<ARA_EquipmentIncubator.QualityVeryPoor>一般</ARA_EquipmentIncubator.QualityVeryPoor>
|
||||
<ARA_EquipmentIncubator.Quality>质量</ARA_EquipmentIncubator.Quality>
|
||||
|
||||
<ARA_EquipmentIncubator.Incubating>正在生产</ARA_EquipmentIncubator.Incubating>
|
||||
<ARA_EquipmentIncubator.Progress>进度</ARA_EquipmentIncubator.Progress>
|
||||
<ARA_EquipmentIncubator.TimeRemaining>剩余时间</ARA_EquipmentIncubator.TimeRemaining>
|
||||
<ARA_EquipmentIncubator.Days>天</ARA_EquipmentIncubator.Days>
|
||||
<ARA_EquipmentIncubator.Hours>小时</ARA_EquipmentIncubator.Hours>
|
||||
<ARA_EquipmentIncubator.Speed>速度</ARA_EquipmentIncubator.Speed>
|
||||
<ARA_EquipmentIncubator.Quality>质量</ARA_EquipmentIncubator.Quality>
|
||||
<ARA_EquipmentIncubator.LarvaOperating>幼虫正在操作</ARA_EquipmentIncubator.LarvaOperating>
|
||||
<ARA_EquipmentIncubator.SRemaining>秒剩余</ARA_EquipmentIncubator.SRemaining>
|
||||
<ARA_EquipmentIncubator.LarvaOnWay>幼虫在途中</ARA_EquipmentIncubator.LarvaOnWay>
|
||||
<ARA_EquipmentIncubator.Target>目标</ARA_EquipmentIncubator.Target>
|
||||
<ARA_EquipmentIncubator.SpeedMultiplier>速度乘数</ARA_EquipmentIncubator.SpeedMultiplier>
|
||||
<ARA_EquipmentIncubator.QualityMultiplier>质量乘数</ARA_EquipmentIncubator.QualityMultiplier>
|
||||
|
||||
<ARA_EquipmentIncubator.CallLarva>呼叫幼虫</ARA_EquipmentIncubator.CallLarva>
|
||||
<ARA_EquipmentIncubator.CancelIncubation>取消生产</ARA_EquipmentIncubator.CancelIncubation>
|
||||
<ARA_EquipmentIncubator.CancelIncubationDesc>取消当前生产过程,卵荚内容物将丢失</ARA_EquipmentIncubator.CancelIncubationDesc>
|
||||
|
||||
<ARA_EquipmentIncubator.IncubateLabel>生产: {0}</ARA_EquipmentIncubator.IncubateLabel>
|
||||
<ARA_EquipmentIncubator.ButtonDesc>选择要生产的装备类型。幼虫将前来激活装备卵荚。</ARA_EquipmentIncubator.ButtonDesc>
|
||||
<ARA_EquipmentIncubator.ButtonLabel>当前选择: {0}</ARA_EquipmentIncubator.ButtonLabel>
|
||||
<ARA_EquipmentIncubator.IncubationTime>生产时间: {0}天</ARA_EquipmentIncubator.IncubationTime>
|
||||
<ARA_EquipmentIncubator.MenuTitle>选择生产目标</ARA_EquipmentIncubator.MenuTitle>
|
||||
<ARA_EquipmentIncubator.ResearchRequired>需要研究: </ARA_EquipmentIncubator.ResearchRequired>
|
||||
<ARA_EquipmentIncubator.TargetSwitched>生产目标已切换为: {0}</ARA_EquipmentIncubator.TargetSwitched>
|
||||
|
||||
<ARA_EquipmentIncubator.IncubationTab>装备生产</ARA_EquipmentIncubator.IncubationTab>
|
||||
<ARA_EquipmentIncubator.NotAnEquipmentOotheca>这不是装备卵荚</ARA_EquipmentIncubator.NotAnEquipmentOotheca>
|
||||
<ARA_EquipmentIncubator.IncubationProgress>生产进度</ARA_EquipmentIncubator.IncubationProgress>
|
||||
<ARA_EquipmentIncubator.IncubationProgressLabel>生产进度</ARA_EquipmentIncubator.IncubationProgressLabel>
|
||||
<ARA_EquipmentIncubator.QualityProgress>质量进度</ARA_EquipmentIncubator.QualityProgress>
|
||||
<ARA_EquipmentIncubator.LarvaIsActivatingOotheca>幼虫正在激活卵荚</ARA_EquipmentIncubator.LarvaIsActivatingOotheca>
|
||||
<ARA_EquipmentIncubator.SecondsRemaining>秒剩余</ARA_EquipmentIncubator.SecondsRemaining>
|
||||
<ARA_EquipmentIncubator.LarvaIsOnTheWay>幼虫在途中</ARA_EquipmentIncubator.LarvaIsOnTheWay>
|
||||
<ARA_EquipmentIncubator.ReadyToIncubate>准备生产</ARA_EquipmentIncubator.ReadyToIncubate>
|
||||
<ARA_EquipmentIncubator.NoIncubationTargetSelected>未选择生产目标</ARA_EquipmentIncubator.NoIncubationTargetSelected>
|
||||
|
||||
<ARA_EquipmentIncubator.IncubationTarget>生产目标:{0}</ARA_EquipmentIncubator.IncubationTarget>
|
||||
<ARA_EquipmentIncubator.Requires>需要</ARA_EquipmentIncubator.Requires>
|
||||
<ARA_EquipmentIncubator.NoDescription>无描述</ARA_EquipmentIncubator.NoDescription>
|
||||
<ARA_EquipmentIncubator.ResearchCompleted>研究: {0} (已完成)</ARA_EquipmentIncubator.ResearchCompleted>
|
||||
<ARA_EquipmentIncubator.ResearchRequired>研究: {0} (需要)</ARA_EquipmentIncubator.ResearchRequired>
|
||||
</LanguageData>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LanguageData>
|
||||
<!-- Need_HoneyProduction.cs 中的翻译键 -->
|
||||
<ARA_HoneyProduction.CurrentLevel>当前储量</ARA_HoneyProduction.CurrentLevel>
|
||||
<ARA_HoneyProduction.Category>储量等级</ARA_HoneyProduction.Category>
|
||||
<ARA_HoneyProduction.Efficiency>生产效率:(饮食消耗速率的)</ARA_HoneyProduction.Efficiency>
|
||||
<ARA_HoneyProduction.FoodDrainRate>食物消耗速率</ARA_HoneyProduction.FoodDrainRate>
|
||||
<ARA_HoneyProduction.HoneyGainRate>蜜罐增长速率</ARA_HoneyProduction.HoneyGainRate>
|
||||
<ARA_HoneyProduction.FullWarning>警告:蜜罐已满,停止生产!</ARA_HoneyProduction.FullWarning>
|
||||
<ARA_HoneyProduction.Full>满仓</ARA_HoneyProduction.Full>
|
||||
<ARA_HoneyProduction.High>高存量</ARA_HoneyProduction.High>
|
||||
<ARA_HoneyProduction.Medium>中存量</ARA_HoneyProduction.Medium>
|
||||
<ARA_HoneyProduction.Low>低存量</ARA_HoneyProduction.Low>
|
||||
<ARA_HoneyProduction.Empty>空仓</ARA_HoneyProduction.Empty>
|
||||
|
||||
<!-- JobDriver_ExtractHoney.cs 中的翻译键 -->
|
||||
<ARA_ExtractHoney_Message>挤出了 {0} 个虫蜜</ARA_ExtractHoney_Message>
|
||||
|
||||
<!-- JobDriver_FeedWithHoney.cs 中的翻译键 -->
|
||||
<ARA_Message_HoneyFed>{0} 用虫蜜喂养了 {1}</ARA_Message_HoneyFed>
|
||||
|
||||
<!-- 工作相关的翻译键 -->
|
||||
<ARA_ExtractHoney>挤出虫蜜</ARA_ExtractHoney>
|
||||
<ARA_FeedWithHoney>用虫蜜喂养</ARA_FeedWithHoney>
|
||||
|
||||
<!-- 通用描述 -->
|
||||
<ARA_HoneyProduction>蜜罐生产</ARA_HoneyProduction>
|
||||
<ARA_InsectJelly>虫蜜</ARA_InsectJelly>
|
||||
</LanguageData>
|
||||
@@ -18,7 +18,7 @@
|
||||
<ARA_NeedSpecificArachnaeToStartIncubation>未孵化,需要 {0} 交互\n\n在生产完成时,剩余的营养将重新转变为物品。</ARA_NeedSpecificArachnaeToStartIncubation>
|
||||
<ARA_AnyArachnaeRace>任何阿拉克涅虫族</ARA_AnyArachnaeRace>
|
||||
<ARA_ItemsAvailable>{0} 个物品可用</ARA_ItemsAvailable>
|
||||
<QualityProgress>物品品质</QualityProgress>
|
||||
<QualityProgress>孵化品质</QualityProgress>
|
||||
|
||||
<!-- Added for CompQueuedPawnSpawner -->
|
||||
<NutritionNeeded>所需营养</NutritionNeeded>
|
||||
@@ -31,4 +31,14 @@
|
||||
<ProductionSlots>生产槽位: {0} / {1}</ProductionSlots>
|
||||
<ProductionQueue>等待队列: {0}</ProductionQueue>
|
||||
<ProductionSpeed>生产速度</ProductionSpeed>
|
||||
|
||||
<ARA_Chitin.ShellParts>甲壳部位数量</ARA_Chitin.ShellParts>
|
||||
<ARA_Chitin.GrowthRate>生长速率</ARA_Chitin.GrowthRate>
|
||||
<ARA_ChitinStripping_Toggle>甲壳剥离</ARA_ChitinStripping_Toggle>
|
||||
<ARA_ChitinStripping_ToggleDesc>切换是否允许此单位自动剥离甲壳。当甲壳过厚,单位会自动剥离甲壳以产生甲壳素。</ARA_ChitinStripping_ToggleDesc>
|
||||
<ARA_StripChitin_Message>剥离了{0}个甲壳</ARA_StripChitin_Message>
|
||||
<ARA_ChitinStripping_Disabled>甲壳剥离功能已禁用</ARA_ChitinStripping_Disabled>
|
||||
<ARA_ChitinStripping_Cooldown>冷却中:{0}秒后可以再次剥离</ARA_ChitinStripping_Cooldown>
|
||||
<ARA_ChitinStripping_Threshold>甲壳存量未达到阈值({0}%)</ARA_ChitinStripping_Threshold>
|
||||
<ARA_ChitinStripping_Ready>可以开始剥离甲壳</ARA_ChitinStripping_Ready>
|
||||
</LanguageData>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LanguageData>
|
||||
<!-- 维护系统翻译 -->
|
||||
<ARA_SwarmMaintenance.MaintenanceLevel>维护度: {0}/{1} ({2})</ARA_SwarmMaintenance.MaintenanceLevel>
|
||||
<ARA_SwarmMaintenance.Depleted>维护度耗尽!建筑正在损坏!</ARA_SwarmMaintenance.Depleted>
|
||||
<ARA_SwarmMaintenance.Critical>维护度严重不足!</ARA_SwarmMaintenance.Critical>
|
||||
<ARA_SwarmMaintenance.NeedsMaintenance>需要维护</ARA_SwarmMaintenance.NeedsMaintenance>
|
||||
<ARA_SwarmMaintenance.DailyDecay>每日维护度递减: {0}</ARA_SwarmMaintenance.DailyDecay>
|
||||
<ARA_SwarmMaintenance.SeekingMaintainer>正在寻找空闲的维护者...</ARA_SwarmMaintenance.SeekingMaintainer>
|
||||
<ARA_SwarmMaintenance.NoMaintainerFound>找不到符合条件的空闲维护者</ARA_SwarmMaintenance.NoMaintainerFound>
|
||||
<ARA_SwarmMaintenance.AllowedRaces>允许维护的种族:</ARA_SwarmMaintenance.AllowedRaces>
|
||||
<ARA_SwarmMaintenance.NoRacesSpecified>未指定可维护的种族</ARA_SwarmMaintenance.NoRacesSpecified>
|
||||
</LanguageData>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LanguageData>
|
||||
<!-- 温度损坏系统翻译 -->
|
||||
<ARA_TemperatureRuinable.SafeTemperatureRange>安全温度范围: {0} - {1}</ARA_TemperatureRuinable.SafeTemperatureRange>
|
||||
<ARA_TemperatureRuinable.CurrentTemperature>当前温度: {0}</ARA_TemperatureRuinable.CurrentTemperature>
|
||||
<ARA_TemperatureRuinable.DamageProgress>损坏进度: {0}</ARA_TemperatureRuinable.DamageProgress>
|
||||
<ARA_TemperatureRuinable.TakingDamage>正在受到温度伤害</ARA_TemperatureRuinable.TakingDamage>
|
||||
<ARA_TemperatureRuinable.NoDamage>未受到温度影响</ARA_TemperatureRuinable.NoDamage>
|
||||
<ARA_TemperatureRuinable.TooCold>过冷</ARA_TemperatureRuinable.TooCold>
|
||||
<ARA_TemperatureRuinable.TooHot>过热</ARA_TemperatureRuinable.TooHot>
|
||||
<ARA_TemperatureRuinable.DamageLetterLabel>{0} 受到温度伤害</ARA_TemperatureRuinable.DamageLetterLabel>
|
||||
<ARA_TemperatureRuinable.DamageLetterText>{0} 因{1}正在受到温度伤害。\n\n当前温度: {2}\n安全温度范围: {3} - {4}\n\n建议尽快调整温度至安全范围,以避免结构损坏。</ARA_TemperatureRuinable.DamageLetterText>
|
||||
</LanguageData>
|
||||
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_CallLarva.png
Normal file
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_CallLarva.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_ShowRadius.png
Normal file
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_ShowRadius.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_StripChitin.png
Normal file
BIN
Content/Textures/ArachnaeSwarm/UI/Commands/ARA_StripChitin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
@@ -1,58 +1,58 @@
|
||||
{
|
||||
"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\\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\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\building_equipmentootheca\\building_equipmentootheca.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|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_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\\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\\thing_comps\\ara_compextraincubationinfo\\compproperties_extraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_compextraincubationinfo\\compproperties_extraincubationinfo.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\\thing_comps\\ara_compextraincubationinfo\\compextraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_compextraincubationinfo\\compextraincubationinfo.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|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\placeworker\\compproperties_customradius.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:placeworker\\compproperties_customradius.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_swarmmaintenance\\comp_swarmmaintenance.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_swarmmaintenance\\comp_swarmmaintenance.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\\flyover\\ara_groundstrafing\\compgroundstrafing.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_groundstrafing\\compgroundstrafing.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_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_sectorsurveillance\\compsectorsurveillance.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_sectorsurveillance\\compsectorsurveillance.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\\comptemperatureruinabledamage.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comptemperatureruinabledamage.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\\flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\thingclassflyover.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\\flyover\\ara_aircrafthangar\\compabilityeffect_aircraftstrike.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\compabilityeffect_aircraftstrike.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_givehediffwithskillduration\\compabilityeffect_givehediffwithskillduration.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_givehediffwithskillduration\\compabilityeffect_givehediffwithskillduration.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_showtemperaturerange\\compabilityeffect_abilityshowtemperaturerange.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\\abilities\\ara_showtemperaturerange\\compabilityeffect_abilityshowtemperaturerange.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_showtemperaturerange\\compabilityeffect_abilityshowtemperaturerange.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_showspawnablepawnslist\\compabilityeffect_abilityshowspawnablepawns.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_showspawnablepawnslist\\compabilityeffect_abilityshowspawnablepawns.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_swarmmaintain\\jobdriver_swarmmaintain.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_swarmmaintain\\jobdriver_swarmmaintain.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\\flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.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\\flyover\\ara_aircrafthangar\\compaircrafthangar.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\compaircrafthangar.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\\flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.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\\flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_flyoverescort\\compproperties_flyoverescort.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_feedwithhoney\\jobdriver_feedwithhoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_feedwithhoney\\jobdriver_feedwithhoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
@@ -62,21 +62,8 @@
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 0,
|
||||
"SelectedChildIndex": 3,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "Building_Ootheca.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
|
||||
"RelativeDocumentMoniker": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Building_Ootheca\\Building_Ootheca.cs",
|
||||
"RelativeToolTip": "Buildings\\Building_Ootheca\\Building_Ootheca.cs",
|
||||
"ViewState": "AgIAAK8CAAAAAAAAAAA9wPACAAAMAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T07:28:18.272Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
||||
@@ -84,147 +71,171 @@
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "CompProperties_CustomRadius.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Placeworker\\CompProperties_CustomRadius.cs",
|
||||
"RelativeDocumentMoniker": "Placeworker\\CompProperties_CustomRadius.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Placeworker\\CompProperties_CustomRadius.cs",
|
||||
"RelativeToolTip": "Placeworker\\CompProperties_CustomRadius.cs",
|
||||
"ViewState": "AgIAAAIAAAAAAAAAAAAAACMAAAA/AAAAAAAAAA==",
|
||||
"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": "AgIAAAQAAAAAAAAAAAAmwDMBAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T07:21:04.756Z",
|
||||
"WhenOpened": "2025-12-15T17:55:40.041Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "CompSectorSurveillance.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs",
|
||||
"ViewState": "AgIAAPACAAAAAAAAAAAAABEDAAAAAAAAAAAAAA==",
|
||||
"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": "AgIAAAAAAAAAAAAAAADwvxgAAAAdAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-30T13:52:54.896Z"
|
||||
"WhenOpened": "2025-12-15T17:32:18.493Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "CompGroundStrafing.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs",
|
||||
"ViewState": "AgIAAGwBAAAAAAAAAAArwIYBAAAFAAAAAAAAAA==",
|
||||
"DocumentIndex": 0,
|
||||
"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": "AgIAADIBAAAAAAAAAAAAAEQBAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-30T13:00:11.18Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "CompAbilityEffect_GiveHediffWithSkillDuration.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
|
||||
"RelativeDocumentMoniker": "Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
|
||||
"RelativeToolTip": "Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
|
||||
"ViewState": "AgIAAEsAAAAAAAAAAAAWwGAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T14:40:47.422Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"RelativeDocumentMoniker": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"RelativeToolTip": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAAArAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T14:40:43.525Z"
|
||||
"WhenOpened": "2025-12-15T17:32:08.87Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"Title": "CompAbilityEffect_AircraftStrike.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
|
||||
"ViewState": "AgIAAHYAAAAAAAAAAAAtwJcAAAArAAAAAAAAAA==",
|
||||
"Title": "CompExtraIncubationInfo.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
|
||||
"RelativeDocumentMoniker": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
|
||||
"RelativeToolTip": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T11:22:34.783Z"
|
||||
"WhenOpened": "2025-12-15T17:13:20.87Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "ThingclassFlyOver.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ThingclassFlyOver.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
|
||||
"RelativeToolTip": "Flyover\\ThingclassFlyOver.cs",
|
||||
"ViewState": "AgIAAIkCAAAAAAAAAAAawI8CAAANAAAAAAAAAA==",
|
||||
"Title": "CompProperties_ExtraIncubationInfo.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
|
||||
"RelativeDocumentMoniker": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
|
||||
"RelativeToolTip": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T14:17:06.867Z"
|
||||
"WhenOpened": "2025-12-15T17:13:20.069Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"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": "AgIAAAAAAAAAAAAAAADwvxIAAAA4AAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T17:11:54.114Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"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": "AgIAAA0DAAAAAAAAAAAAACAAAAArAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T17:10:05.509Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "Comp_SwarmMaintenance.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_SwarmMaintenance\\Comp_SwarmMaintenance.cs",
|
||||
"RelativeDocumentMoniker": "Building_Comps\\ARA_SwarmMaintenance\\Comp_SwarmMaintenance.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_SwarmMaintenance\\Comp_SwarmMaintenance.cs",
|
||||
"RelativeToolTip": "Building_Comps\\ARA_SwarmMaintenance\\Comp_SwarmMaintenance.cs",
|
||||
"ViewState": "AgIAABkBAAAAAAAAAAAAAE0BAABIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T16:59:28.717Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "CompAbilityEffect_AbilityShowSpawnablePawns.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
|
||||
"RelativeDocumentMoniker": "Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
|
||||
"RelativeToolTip": "Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
|
||||
"ViewState": "AgIAABYAAAAAAAAAAAAuwBYAAAArAAAAAAAAAA==",
|
||||
"Title": "CompDelayedTerrainSpawn.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
|
||||
"RelativeDocumentMoniker": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
|
||||
"RelativeToolTip": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T14:40:40.237Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"Title": "CompAircraftHangar.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
|
||||
"ViewState": "AgIAABcAAAAAAAAAAAAQwCQAAAAnAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T11:39:22.563Z"
|
||||
"WhenOpened": "2025-12-15T16:59:21.314Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "CompAbilityEffect_SpawnFlyOver.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
|
||||
"ViewState": "AgIAAFMDAAAAAAAAAAAawG8DAAAAAAAAAAAAAA==",
|
||||
"Title": "CompTemperatureRuinableDamage.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompTemperatureRuinableDamage.cs",
|
||||
"RelativeDocumentMoniker": "Building_Comps\\CompTemperatureRuinableDamage.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompTemperatureRuinableDamage.cs",
|
||||
"RelativeToolTip": "Building_Comps\\CompTemperatureRuinableDamage.cs",
|
||||
"ViewState": "AgIAAB8AAAAAAAAAAAAAwDoAAAAlAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T13:37:35.758Z"
|
||||
"WhenOpened": "2025-12-15T16:52:05.743Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"Title": "CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"RelativeDocumentMoniker": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"RelativeToolTip": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
|
||||
"ViewState": "AgIAAHUAAAAAAAAAAAAAAJIAAABEAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-12-15T16:52:00.971Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"Title": "WorldComponent_AircraftManager.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
|
||||
"ViewState": "AgIAAJUAAAAAAAAAAAAowK4AAAAUAAAAAAAAAA==",
|
||||
"Title": "JobDriver_SwarmMaintain.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
|
||||
"RelativeDocumentMoniker": "Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
|
||||
"RelativeToolTip": "Jobs\\JobDriver_SwarmMaintain\\JobDriver_SwarmMaintain.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAB0AAABPAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T14:05:39.817Z"
|
||||
"WhenOpened": "2025-12-15T16:36:34.047Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 12,
|
||||
"Title": "CompProperties_FlyOverEscort.cs",
|
||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||
"RelativeDocumentMoniker": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||
"RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAvAAAAAAAAAA==",
|
||||
"Title": "JobDriver_FeedWithHoney.cs",
|
||||
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
|
||||
"RelativeDocumentMoniker": "Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
|
||||
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
|
||||
"RelativeToolTip": "Jobs\\JobDriver_FeedWithHoney\\JobDriver_FeedWithHoney.cs",
|
||||
"ViewState": "AgIAACEAAAAAAAAAAAAYwEsAAAAOAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-29T12:59:07.753Z"
|
||||
"WhenOpened": "2025-12-15T16:35:50.511Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -19,10 +19,22 @@ namespace ArachnaeSwarm
|
||||
public static class ARA_JobDefOf
|
||||
{
|
||||
public static JobDef ARA_OperateIncubator;
|
||||
|
||||
public static JobDef ARA_OperateEquipmentIncubator;
|
||||
public static JobDef ARA_SwarmMaintain;
|
||||
|
||||
static ARA_JobDefOf()
|
||||
{
|
||||
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_JobDefOf));
|
||||
}
|
||||
}
|
||||
[DefOf]
|
||||
public static class ARA_EffecterDefOf
|
||||
{
|
||||
public static EffecterDef EatVegetarian;
|
||||
|
||||
static ARA_EffecterDefOf()
|
||||
{
|
||||
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_EffecterDefOf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,11 +114,16 @@
|
||||
<Compile Include="Abilities\CompAbilityEffect_RandomHediff.cs" />
|
||||
<Compile Include="Abilities\CompAbilityEffect_TransformCorpse.cs" />
|
||||
<Compile Include="Buildings\Building_ArachnaeGravEngine.cs" />
|
||||
<Compile Include="Buildings\Building_EquipmentOotheca\Building_EquipmentOotheca.cs" />
|
||||
<Compile Include="Buildings\Building_EquipmentOotheca\CompProperties_EquipmentIncubatorData.cs" />
|
||||
<Compile Include="Buildings\Building_EquipmentOotheca\ITab_EquipmentOotheca_Incubation.cs" />
|
||||
<Compile Include="Buildings\Building_EquipmentOotheca\JobDriver_OperateEquipmentIncubator.cs" />
|
||||
<Compile Include="Buildings\Building_Incubatable.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\Building_Ootheca.cs" />
|
||||
<Compile Include="Buildings\Building_Ootheca\CompProperties_IncubatorData.cs" />
|
||||
<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="Buildings\Building_TurretGunHasSpeed.cs" />
|
||||
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\Building_RefuelingVat.cs" />
|
||||
@@ -131,6 +136,8 @@
|
||||
<Compile Include="Building_Comps\ARA_ForwardClearance\PlaceWorker_ForwardClearance.cs" />
|
||||
<Compile Include="Building_Comps\ARA_ProductStorage\CompProductStorage.cs" />
|
||||
<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\CompBreakdownDisabler.cs" />
|
||||
<Compile Include="EventSystem\CompOpenCustomUI.cs" />
|
||||
<Compile Include="EventSystem\Condition.cs" />
|
||||
@@ -164,7 +171,18 @@
|
||||
<Compile Include="Hediffs\ARA_HediffTerrainSpawn\CompProperties_HediffTerrainSpawn.cs" />
|
||||
<Compile Include="Hediffs\HediffComp_LifespanDisplay.cs" />
|
||||
<Compile Include="Jobs\JobDriver_CarryPrisonerToRefuelingVat.cs" />
|
||||
<Compile Include="Jobs\JobDriver_FeedWithHoney\JobDriver_ExtractHoney.cs" />
|
||||
<Compile Include="Jobs\JobDriver_FeedWithHoney\JobDriver_FeedWithHoney.cs" />
|
||||
<Compile Include="Jobs\JobDriver_FeedWithHoney\ThinkNode_JobGiver_ExtractHoney.cs" />
|
||||
<Compile Include="Jobs\JobDriver_FeedWithHoney\ThinkNode_JobGiver_FeedWithHoney.cs" />
|
||||
<Compile Include="Jobs\JobDriver_StripChitin\CompProperties_ChitinStripping.cs" />
|
||||
<Compile Include="Jobs\JobDriver_StripChitin\Comp_ChitinStripping.cs" />
|
||||
<Compile Include="Jobs\JobDriver_StripChitin\JobDriver_StripChitin.cs" />
|
||||
<Compile Include="Jobs\JobDriver_StripChitin\ThinkNode_JobGiver_StripChitin.cs" />
|
||||
<Compile Include="Jobs\JobDriver_SwarmMaintain\JobDriver_SwarmMaintain.cs" />
|
||||
<Compile Include="MentalState\MentalState_HiveMindCascade.cs" />
|
||||
<Compile Include="Needs\Need_ChitinArmor.cs" />
|
||||
<Compile Include="Needs\Need_HoneyProduction.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_UniquePawn\CompProperties_UniquePawn.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_UniquePawn\CompUniquePawn.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_UniquePawn\Patch_UniquePawn.cs" />
|
||||
@@ -196,7 +214,7 @@
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\CompInteractiveProducer.cs" />
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\CompQueuedInteractiveProducer.cs" />
|
||||
<Compile Include="Building_Comps\CompRefuelableNutrition.cs" />
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\CompTemperatureRuinableDamage.cs" />
|
||||
<Compile Include="Building_Comps\CompTemperatureRuinableDamage.cs" />
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\DataContracts.cs" />
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\JobDriver_AddProcessToQueue.cs" />
|
||||
<Compile Include="Building_Comps\ARA_CompInteractiveProducer\JobDriver_StartProduction.cs" />
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_TemperatureRuinableDamage : CompProperties
|
||||
{
|
||||
public float minSafeTemperature;
|
||||
public float maxSafeTemperature = 100f;
|
||||
public float progressPerDegreePerTick = 1E-05f; // 修改参数名以匹配标准调用方式
|
||||
public float damagePerTick = 1f; // 每tick造成的伤害值
|
||||
public float recoveryRate = 0.001f; // 温度恢复正常时的恢复速率
|
||||
|
||||
public CompProperties_TemperatureRuinableDamage()
|
||||
{
|
||||
compClass = typeof(CompTemperatureRuinableDamage);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompTemperatureRuinableDamage : ThingComp
|
||||
{
|
||||
private float ruinedPercent; // 修改变量名以匹配标准
|
||||
private bool isRuined; // 修改变量名以匹配标准
|
||||
|
||||
public CompProperties_TemperatureRuinableDamage Props => (CompProperties_TemperatureRuinableDamage)props;
|
||||
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
if (parent.AmbientTemperature < Props.minSafeTemperature || parent.AmbientTemperature > Props.maxSafeTemperature)
|
||||
{
|
||||
float tempDelta = 0f;
|
||||
if (parent.AmbientTemperature < Props.minSafeTemperature)
|
||||
{
|
||||
tempDelta = Props.minSafeTemperature - parent.AmbientTemperature;
|
||||
}
|
||||
else if (parent.AmbientTemperature > Props.maxSafeTemperature)
|
||||
{
|
||||
tempDelta = parent.AmbientTemperature - Props.maxSafeTemperature;
|
||||
}
|
||||
|
||||
// 累积损坏进度
|
||||
ruinedPercent += tempDelta * Props.progressPerDegreePerTick;
|
||||
|
||||
// 只有在已损坏的情况下才每tick造成持续伤害
|
||||
if (isRuined)
|
||||
{
|
||||
parent.TakeDamage(new DamageInfo(DamageDefOf.Deterioration, Props.damagePerTick));
|
||||
}
|
||||
|
||||
// 标记为已受损
|
||||
isRuined = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当温度恢复正常时,逐渐减少损坏进度而不是重置
|
||||
if (isRuined && ruinedPercent > 0f)
|
||||
{
|
||||
ruinedPercent -= Props.recoveryRate;
|
||||
if (ruinedPercent <= 0f)
|
||||
{
|
||||
ruinedPercent = 0f;
|
||||
isRuined = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 即使温度正常,如果已损坏也要继续造成伤害直到恢复
|
||||
if (isRuined)
|
||||
{
|
||||
parent.TakeDamage(new DamageInfo(DamageDefOf.Deterioration, Props.damagePerTick));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref ruinedPercent, "ruinedPercent", 0f);
|
||||
Scribe_Values.Look(ref isRuined, "isRuined", false);
|
||||
}
|
||||
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
if (ruinedPercent > 0f)
|
||||
{
|
||||
return "CocoonRuinedByTemperature".Translate() + ": " + ruinedPercent.ToStringPercent();
|
||||
}
|
||||
return base.CompInspectStringExtra();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// File: Comps/CompProperties_SwarmMaintenance.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_SwarmMaintenance : CompProperties
|
||||
{
|
||||
// 最大维护度
|
||||
public float maxMaintenance = 100f;
|
||||
|
||||
// 每天下降的维护度
|
||||
public float maintenanceDecayPerDay = 10f;
|
||||
|
||||
// 维护度为0时每秒受到的伤害
|
||||
public float damagePerSecondWhenEmpty = 1f;
|
||||
|
||||
// 维护度达到多少时开始显示警告(百分比)
|
||||
public float warningThreshold = 0.3f;
|
||||
|
||||
// 可维护的种族列表
|
||||
public List<ThingDef> allowedRaces;
|
||||
|
||||
// 检查分配工作的间隔(ticks)
|
||||
public int assignJobCheckInterval = 600; // 10秒
|
||||
|
||||
// 维护度低于多少时开始寻找维护者(百分比)
|
||||
public float maintenanceThresholdForJob = 0.9f;
|
||||
|
||||
public CompProperties_SwarmMaintenance()
|
||||
{
|
||||
compClass = typeof(Comp_SwarmMaintenance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
// File: Comps/Comp_SwarmMaintenance.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class Comp_SwarmMaintenance : ThingComp
|
||||
{
|
||||
// 属性访问器
|
||||
public CompProperties_SwarmMaintenance Props => (CompProperties_SwarmMaintenance)props;
|
||||
|
||||
// 当前维护度
|
||||
private float currentMaintenance;
|
||||
|
||||
// 上次更新维护度的时间
|
||||
private int lastMaintenanceTick = -99999;
|
||||
|
||||
// 上次检查分配工作的时间
|
||||
private int lastJobCheckTick = -99999;
|
||||
|
||||
// 当维护度为0时,每秒受到的伤害计时器
|
||||
private int nextDamageTick = -99999;
|
||||
|
||||
// 是否正在寻找维护者
|
||||
private bool seekingMaintainer = false;
|
||||
|
||||
// 找不到维护者的提示信息
|
||||
private string noMaintainerWarning = "";
|
||||
private int lastWarningTick = -99999;
|
||||
private const int WarningDuration = 2500; // 警告显示41.67秒
|
||||
|
||||
// 属性访问
|
||||
public float CurrentMaintenance => currentMaintenance;
|
||||
public float MaxMaintenance => Props.maxMaintenance;
|
||||
public float MaintenancePercentage => currentMaintenance / MaxMaintenance;
|
||||
public bool NeedsMaintenance => currentMaintenance < MaxMaintenance * Props.maintenanceThresholdForJob;
|
||||
public bool IsCritical => currentMaintenance <= MaxMaintenance * Props.warningThreshold;
|
||||
public bool IsEmpty => currentMaintenance <= 0f;
|
||||
|
||||
// 初始化
|
||||
public override void Initialize(CompProperties props)
|
||||
{
|
||||
base.Initialize(props);
|
||||
currentMaintenance = Props.maxMaintenance; // 初始时满维护度
|
||||
lastMaintenanceTick = Find.TickManager.TicksGame;
|
||||
lastJobCheckTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
|
||||
// 序列化
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref currentMaintenance, "currentMaintenance", Props.maxMaintenance);
|
||||
Scribe_Values.Look(ref lastMaintenanceTick, "lastMaintenanceTick", -99999);
|
||||
Scribe_Values.Look(ref lastJobCheckTick, "lastJobCheckTick", -99999);
|
||||
Scribe_Values.Look(ref nextDamageTick, "nextDamageTick", -99999);
|
||||
Scribe_Values.Look(ref seekingMaintainer, "seekingMaintainer", false);
|
||||
Scribe_Values.Look(ref noMaintainerWarning, "noMaintainerWarning", "");
|
||||
Scribe_Values.Look(ref lastWarningTick, "lastWarningTick", -99999);
|
||||
}
|
||||
|
||||
// 每tick更新
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
|
||||
// 每2500tick(约41.67秒)更新一次维护度递减
|
||||
if (currentTick - lastMaintenanceTick >= 2500)
|
||||
{
|
||||
UpdateMaintenanceDecay();
|
||||
lastMaintenanceTick = currentTick;
|
||||
}
|
||||
|
||||
// 定期检查是否需要分配维护工作
|
||||
if (currentTick - lastJobCheckTick >= Props.assignJobCheckInterval)
|
||||
{
|
||||
CheckAndAssignMaintenanceJob();
|
||||
lastJobCheckTick = currentTick;
|
||||
}
|
||||
|
||||
// 如果维护度为0,每秒造成伤害
|
||||
if (currentMaintenance <= 0f && currentTick >= nextDamageTick)
|
||||
{
|
||||
ApplyDamageWhenEmpty();
|
||||
nextDamageTick = currentTick + 60; // 60ticks = 1秒
|
||||
}
|
||||
|
||||
// 更新警告信息显示时间
|
||||
if (currentTick - lastWarningTick >= WarningDuration)
|
||||
{
|
||||
noMaintainerWarning = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 更新维护度递减
|
||||
private void UpdateMaintenanceDecay()
|
||||
{
|
||||
if (parent == null || parent.Map == null)
|
||||
return;
|
||||
|
||||
// 计算递减量:每天递减量转换为每2500tick(约0.347天)的递减量
|
||||
float decayAmount = Props.maintenanceDecayPerDay * (2500f / 60000f);
|
||||
currentMaintenance -= decayAmount;
|
||||
|
||||
// 确保不低于0
|
||||
if (currentMaintenance < 0f)
|
||||
currentMaintenance = 0f;
|
||||
}
|
||||
|
||||
// 当维护度为0时应用伤害
|
||||
private void ApplyDamageWhenEmpty()
|
||||
{
|
||||
if (parent == null || parent.Destroyed)
|
||||
return;
|
||||
|
||||
// 每秒造成伤害
|
||||
float damageAmount = Props.damagePerSecondWhenEmpty;
|
||||
|
||||
// 应用伤害到建筑
|
||||
parent.TakeDamage(new DamageInfo(
|
||||
DamageDefOf.Deterioration,
|
||||
damageAmount,
|
||||
armorPenetration: 999f, // 高穿甲,确保能造成伤害
|
||||
instigator: null
|
||||
));
|
||||
}
|
||||
|
||||
// 检查并分配维护工作
|
||||
private void CheckAndAssignMaintenanceJob()
|
||||
{
|
||||
if (parent == null || parent.Map == null || parent.Faction == null)
|
||||
return;
|
||||
|
||||
// 如果不需要维护,重置状态
|
||||
if (!NeedsMaintenance)
|
||||
{
|
||||
seekingMaintainer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果正在寻找维护者,尝试分配工作
|
||||
if (!seekingMaintainer)
|
||||
{
|
||||
seekingMaintainer = true;
|
||||
}
|
||||
|
||||
// 尝试寻找符合条件的Pawn
|
||||
Pawn maintainer = FindAvailableMaintainer();
|
||||
|
||||
if (maintainer != null)
|
||||
{
|
||||
// 分配维护工作
|
||||
AssignMaintenanceJobTo(maintainer);
|
||||
seekingMaintainer = false;
|
||||
noMaintainerWarning = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 记录找不到维护者的警告
|
||||
if (noMaintainerWarning == "")
|
||||
{
|
||||
noMaintainerWarning = "ARA_SwarmMaintenance.NoMaintainerFound".Translate();
|
||||
lastWarningTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 寻找可用的维护者
|
||||
private Pawn FindAvailableMaintainer()
|
||||
{
|
||||
if (parent.Map == null || parent.Faction == null)
|
||||
return null;
|
||||
|
||||
// 查找地图中所有属于玩家阵营的Pawn
|
||||
List<Pawn> allPawns = parent.Map.mapPawns.SpawnedPawnsInFaction(parent.Faction);
|
||||
|
||||
foreach (Pawn pawn in allPawns)
|
||||
{
|
||||
if (CanPawnMaintain(pawn))
|
||||
{
|
||||
return pawn;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 判断Pawn是否可以维护
|
||||
private bool CanPawnMaintain(Pawn pawn)
|
||||
{
|
||||
if (pawn == null || pawn.Dead || pawn.Downed || pawn.InMentalState)
|
||||
return false;
|
||||
|
||||
// 检查种族是否在允许列表中
|
||||
if (Props.allowedRaces != null && Props.allowedRaces.Count > 0)
|
||||
{
|
||||
if (!Props.allowedRaces.Contains(pawn.def))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Pawn是否处于GotoWander或Wait_Wander状态
|
||||
if (!IsPawnWandering(pawn))
|
||||
return false;
|
||||
|
||||
// 检查Pawn是否已经有维护工作
|
||||
if (HasMaintenanceJob(pawn))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查Pawn是否处于漫游状态
|
||||
private bool IsPawnWandering(Pawn pawn)
|
||||
{
|
||||
if (pawn.jobs == null || pawn.jobs.curJob == null)
|
||||
return false;
|
||||
|
||||
Job curJob = pawn.jobs.curJob;
|
||||
|
||||
// 检查是否是漫游工作
|
||||
if (curJob.def == JobDefOf.GotoWander || curJob.def == JobDefOf.Wait_Wander)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Pawn是否已经有维护工作
|
||||
private bool HasMaintenanceJob(Pawn pawn)
|
||||
{
|
||||
if (pawn.jobs == null)
|
||||
return false;
|
||||
|
||||
// 检查当前工作是否是维护工作
|
||||
if (pawn.jobs.curJob != null && pawn.jobs.curJob.def == ARA_JobDefOf.ARA_SwarmMaintain)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查工作队列中是否有维护工作
|
||||
if (pawn.jobs.jobQueue != null && pawn.jobs.jobQueue.Count > 0)
|
||||
{
|
||||
foreach (QueuedJob queuedJob in pawn.jobs.jobQueue)
|
||||
{
|
||||
if (queuedJob.job.def == ARA_JobDefOf.ARA_SwarmMaintain)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 为Pawn分配维护工作
|
||||
private void AssignMaintenanceJobTo(Pawn pawn)
|
||||
{
|
||||
if (pawn == null || pawn.jobs == null)
|
||||
return;
|
||||
|
||||
// 创建维护工作
|
||||
Job job = JobMaker.MakeJob(ARA_JobDefOf.ARA_SwarmMaintain, parent);
|
||||
job.expiryInterval = 30000; // 工作过期时间
|
||||
job.ignoreForbidden = false;
|
||||
|
||||
// 记录Pawn原来的工作以便恢复
|
||||
Job oldJob = pawn.jobs.curJob;
|
||||
|
||||
// 将工作添加到队列末尾
|
||||
pawn.jobs.TryTakeOrderedJob(job, JobTag.MiscWork);
|
||||
|
||||
// 如果Pawn原来在漫游,我们可以在维护工作完成后恢复漫游状态
|
||||
if (oldJob != null && (oldJob.def == JobDefOf.GotoWander || oldJob.def == JobDefOf.Wait_Wander))
|
||||
{
|
||||
// 我们可以在维护工作完成后添加一个恢复漫游的工作
|
||||
// 这里暂时不做处理,因为维护工作完成后Pawn会回到空闲状态
|
||||
// 如果需要更精细的控制,可以在JobDriver_SwarmMaintain完成时添加漫游工作
|
||||
}
|
||||
}
|
||||
|
||||
// 添加维护度
|
||||
public void AddMaintenance(float amount)
|
||||
{
|
||||
currentMaintenance += amount;
|
||||
if (currentMaintenance > MaxMaintenance)
|
||||
currentMaintenance = MaxMaintenance;
|
||||
}
|
||||
|
||||
// 重置维护度
|
||||
public void ResetMaintenance()
|
||||
{
|
||||
currentMaintenance = MaxMaintenance;
|
||||
}
|
||||
|
||||
// 在建筑信息面板中追加维护信息
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
// 基础信息
|
||||
string text = "ARA_SwarmMaintenance.MaintenanceLevel".Translate(currentMaintenance.ToString("F1"), MaxMaintenance.ToString("F1"), MaintenancePercentage.ToString("P1"));
|
||||
|
||||
// 添加维护度递减信息
|
||||
text += "\n" + "ARA_SwarmMaintenance.DailyDecay".Translate(Props.maintenanceDecayPerDay.ToString("F1"));
|
||||
|
||||
|
||||
// 显示找不到维护者的警告
|
||||
if (noMaintainerWarning != "")
|
||||
{
|
||||
text += "\n<color=orange>" + noMaintainerWarning + "</color>";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// 获取Gizmos(命令按钮)- 只保留调试功能
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
// 只在玩家控制下显示
|
||||
if (parent.Faction?.IsPlayer == true)
|
||||
{
|
||||
// 调试按钮:手动触发寻找维护者
|
||||
if (Prefs.DevMode)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "Debug: Find Maintainer",
|
||||
action = () =>
|
||||
{
|
||||
Pawn maintainer = FindAvailableMaintainer();
|
||||
if (maintainer != null)
|
||||
{
|
||||
Messages.Message($"找到维护者: {maintainer.LabelShort} (当前工作: {maintainer.jobs.curJob?.def.defName ?? "无"})", MessageTypeDefOf.PositiveEvent);
|
||||
AssignMaintenanceJobTo(maintainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Messages.Message("未找到符合条件的空闲维护者", MessageTypeDefOf.NegativeEvent);
|
||||
|
||||
// 列出所有符合条件的Pawn及其状态
|
||||
List<Pawn> allPawns = parent.Map.mapPawns.SpawnedPawnsInFaction(parent.Faction);
|
||||
List<string> pawnStatus = new List<string>();
|
||||
|
||||
foreach (Pawn pawn in allPawns)
|
||||
{
|
||||
if (Props.allowedRaces != null && Props.allowedRaces.Count > 0 && !Props.allowedRaces.Contains(pawn.def))
|
||||
continue;
|
||||
|
||||
string status = $"{pawn.LabelShort}: ";
|
||||
if (pawn.Dead) status += "死亡";
|
||||
else if (pawn.Downed) status += "倒地";
|
||||
else if (pawn.InMentalState) status += "精神崩溃";
|
||||
else if (pawn.jobs?.curJob != null)
|
||||
{
|
||||
status += $"{pawn.jobs.curJob.def.defName}";
|
||||
if (HasMaintenanceJob(pawn)) status += " (已有维护工作)";
|
||||
}
|
||||
else
|
||||
{
|
||||
status += "空闲";
|
||||
}
|
||||
|
||||
pawnStatus.Add(status);
|
||||
}
|
||||
|
||||
if (pawnStatus.Count > 0)
|
||||
{
|
||||
Messages.Message("符合条件的Pawn状态:\n" + string.Join("\n", pawnStatus), MessageTypeDefOf.SilentInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "Debug: Reset Maintenance",
|
||||
action = () => ResetMaintenance()
|
||||
};
|
||||
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "Debug: Reduce 50%",
|
||||
action = () => currentMaintenance = MaxMaintenance * 0.5f
|
||||
};
|
||||
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "Debug: Reduce to 0",
|
||||
action = () => currentMaintenance = 0f
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// File: Comps/CompTemperatureRuinableDamage.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_TemperatureRuinableDamage : CompProperties
|
||||
{
|
||||
public float minSafeTemperature;
|
||||
public float maxSafeTemperature = 100f;
|
||||
public float progressPerDegreePerTick = 1E-05f; // 修改参数名以匹配标准调用方式
|
||||
public float damagePerTick = 1f; // 每tick造成的伤害值
|
||||
public float recoveryRate = 0.001f; // 温度恢复正常时的恢复速率
|
||||
public bool sendDamageLetter = true; // 是否发送伤害警告信件
|
||||
|
||||
public CompProperties_TemperatureRuinableDamage()
|
||||
{
|
||||
compClass = typeof(CompTemperatureRuinableDamage);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompTemperatureRuinableDamage : ThingComp
|
||||
{
|
||||
private float ruinedPercent; // 修改变量名以匹配标准
|
||||
private bool isRuined; // 修改变量名以匹配标准
|
||||
private bool damageLetterSent = false; // 是否已发送伤害警告信件
|
||||
private int lastDamageTick = -99999; // 上次造成伤害的时间
|
||||
private const int DamageLetterInterval = 60000; // 伤害信件间隔(60秒游戏时间)
|
||||
|
||||
public CompProperties_TemperatureRuinableDamage Props => (CompProperties_TemperatureRuinableDamage)props;
|
||||
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
bool wasRuined = isRuined;
|
||||
|
||||
if (parent.AmbientTemperature < Props.minSafeTemperature || parent.AmbientTemperature > Props.maxSafeTemperature)
|
||||
{
|
||||
float tempDelta = 0f;
|
||||
if (parent.AmbientTemperature < Props.minSafeTemperature)
|
||||
{
|
||||
tempDelta = Props.minSafeTemperature - parent.AmbientTemperature;
|
||||
}
|
||||
else if (parent.AmbientTemperature > Props.maxSafeTemperature)
|
||||
{
|
||||
tempDelta = parent.AmbientTemperature - Props.maxSafeTemperature;
|
||||
}
|
||||
|
||||
// 累积损坏进度
|
||||
ruinedPercent += tempDelta * Props.progressPerDegreePerTick;
|
||||
|
||||
// 只有在已损坏的情况下才每tick造成持续伤害
|
||||
if (isRuined)
|
||||
{
|
||||
parent.TakeDamage(new DamageInfo(DamageDefOf.Deterioration, Props.damagePerTick));
|
||||
lastDamageTick = currentTick;
|
||||
|
||||
// 发送伤害警告信件(如果启用)
|
||||
if (Props.sendDamageLetter && !damageLetterSent && currentTick - lastDamageTick >= DamageLetterInterval)
|
||||
{
|
||||
SendDamageLetter();
|
||||
damageLetterSent = true;
|
||||
lastDamageTick = currentTick;
|
||||
}
|
||||
}
|
||||
|
||||
// 标记为已受损
|
||||
isRuined = true;
|
||||
|
||||
// 如果是刚刚变为损坏状态,发送警告信件
|
||||
if (!wasRuined && Props.sendDamageLetter)
|
||||
{
|
||||
SendDamageLetter();
|
||||
damageLetterSent = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当温度恢复正常时,逐渐减少损坏进度而不是重置
|
||||
if (isRuined && ruinedPercent > 0f)
|
||||
{
|
||||
ruinedPercent -= Props.recoveryRate;
|
||||
if (ruinedPercent <= 0f)
|
||||
{
|
||||
ruinedPercent = 0f;
|
||||
isRuined = false;
|
||||
damageLetterSent = false; // 重置信件状态,以便下次损坏时可以再次发送
|
||||
}
|
||||
}
|
||||
|
||||
// 即使温度正常,如果已损坏也要继续造成伤害直到恢复
|
||||
if (isRuined)
|
||||
{
|
||||
parent.TakeDamage(new DamageInfo(DamageDefOf.Deterioration, Props.damagePerTick));
|
||||
lastDamageTick = currentTick;
|
||||
|
||||
// 发送伤害警告信件(如果启用)
|
||||
if (Props.sendDamageLetter && !damageLetterSent && currentTick - lastDamageTick >= DamageLetterInterval)
|
||||
{
|
||||
SendDamageLetter();
|
||||
damageLetterSent = true;
|
||||
lastDamageTick = currentTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref ruinedPercent, "ruinedPercent", 0f);
|
||||
Scribe_Values.Look(ref isRuined, "isRuined", false);
|
||||
Scribe_Values.Look(ref damageLetterSent, "damageLetterSent", false);
|
||||
Scribe_Values.Look(ref lastDamageTick, "lastDamageTick", -99999);
|
||||
}
|
||||
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
// 总是显示安全温度范围
|
||||
string text = "ARA_TemperatureRuinable.SafeTemperatureRange".Translate(
|
||||
Props.minSafeTemperature.ToStringTemperature("F1"),
|
||||
Props.maxSafeTemperature.ToStringTemperature("F1")
|
||||
);
|
||||
|
||||
// 显示当前温度状态
|
||||
text += "\n" + "ARA_TemperatureRuinable.CurrentTemperature".Translate(parent.AmbientTemperature.ToStringTemperature("F1"));
|
||||
|
||||
// 显示损坏状态
|
||||
if (ruinedPercent > 0f)
|
||||
{
|
||||
text += "\n" + "ARA_TemperatureRuinable.DamageProgress".Translate(ruinedPercent.ToStringPercent());
|
||||
|
||||
if (isRuined)
|
||||
{
|
||||
text += "\n<color=red>" + "ARA_TemperatureRuinable.TakingDamage".Translate() + "</color>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text += "\n" + "ARA_TemperatureRuinable.NoDamage".Translate();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// 发送伤害警告信件
|
||||
private void SendDamageLetter()
|
||||
{
|
||||
if (parent == null || parent.Map == null)
|
||||
return;
|
||||
|
||||
// 确定伤害类型(太冷或太热)
|
||||
string temperatureType;
|
||||
if (parent.AmbientTemperature < Props.minSafeTemperature)
|
||||
{
|
||||
temperatureType = "ARA_TemperatureRuinable.TooCold".Translate();
|
||||
}
|
||||
else
|
||||
{
|
||||
temperatureType = "ARA_TemperatureRuinable.TooHot".Translate();
|
||||
}
|
||||
|
||||
// 创建信件
|
||||
string label = "ARA_TemperatureRuinable.DamageLetterLabel".Translate(parent.Label);
|
||||
string text = "ARA_TemperatureRuinable.DamageLetterText".Translate(
|
||||
parent.Label,
|
||||
temperatureType,
|
||||
parent.AmbientTemperature.ToStringTemperature("F1"),
|
||||
Props.minSafeTemperature.ToStringTemperature("F1"),
|
||||
Props.maxSafeTemperature.ToStringTemperature("F1")
|
||||
);
|
||||
|
||||
// 发送信件
|
||||
Find.LetterStack.ReceiveLetter(label, text, LetterDefOf.NegativeEvent, new LookTargets(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,882 @@
|
||||
// File: Buildings/Building_EquipmentOotheca.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
using System;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class Building_EquipmentOotheca : Building
|
||||
{
|
||||
// 引用组件
|
||||
public CompEquipmentIncubatorData EquipmentIncubatorData => this.TryGetComp<CompEquipmentIncubatorData>();
|
||||
|
||||
// 孵化状态
|
||||
public bool isIncubating = false;
|
||||
public float incubationProgress = 0f;
|
||||
public float incubationDuration = 0f;
|
||||
public ThingDef incubatingThingDef = null;
|
||||
|
||||
// 幼虫交互相关
|
||||
public Pawn assignedLarva = null;
|
||||
public int larvaOperateTicksRemaining = 0;
|
||||
|
||||
// 速度乘数系统
|
||||
private float speedMultiplier = 1.0f;
|
||||
private int lastMultiplierUpdateTick = -1;
|
||||
private const int MultiplierUpdateInterval = 250;
|
||||
|
||||
// 质量系统
|
||||
private float qualityMultiplier = 1.0f;
|
||||
private float qualityProgress = 0f;
|
||||
private float qualityTotal = 0f;
|
||||
|
||||
// 缓存的ModExtension
|
||||
private OothecaIncubatorExtension cachedExtension;
|
||||
|
||||
// 获取ModExtension的辅助属性
|
||||
private OothecaIncubatorExtension Ext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedExtension == null)
|
||||
{
|
||||
cachedExtension = def.GetModExtension<OothecaIncubatorExtension>() ?? OothecaIncubatorExtension.Default;
|
||||
}
|
||||
return cachedExtension;
|
||||
}
|
||||
}
|
||||
|
||||
// 属性访问器
|
||||
public float SpeedMultiplier
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
|
||||
{
|
||||
UpdateSpeedMultiplier();
|
||||
}
|
||||
return speedMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// 质量属性
|
||||
public float QualityMultiplier => qualityMultiplier;
|
||||
public float QualityProgress => qualityProgress;
|
||||
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
|
||||
|
||||
// 进度百分比
|
||||
public float AdjustedProgressPercent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (incubationDuration <= 0) return 0f;
|
||||
return incubationProgress / incubationDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取速度因子描述
|
||||
public string GetSpeedFactorsDescription()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("ARA_EquipmentIncubator.SpeedFactors".Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
// 1. 检查是否在孵化间中
|
||||
bool inIncubatorRoom = IsInIncubatorRoom();
|
||||
if (Ext.requiresIncubatorRoom)
|
||||
{
|
||||
builder.AppendLine(inIncubatorRoom ?
|
||||
"ARA_EquipmentIncubator.InIncubatorRoom".Translate() :
|
||||
"ARA_EquipmentIncubator.NotInIncubatorRoom".Translate());
|
||||
}
|
||||
|
||||
// 2. 检查营养液数量
|
||||
int nutrientSolutionCount = CountNearbyNutrientSolutions();
|
||||
if (nutrientSolutionCount > 0)
|
||||
{
|
||||
builder.AppendLine("ARA_EquipmentIncubator.NutrientSolutions".Translate(
|
||||
nutrientSolutionCount,
|
||||
nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile * 100));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine("ARA_EquipmentIncubator.NoNutrientSolutionsNearby".Translate());
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.NutrientDetectionRadius".Translate(Ext.nutrientSolutionRadius));
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.TotalSpeedMultiplier".Translate(SpeedMultiplier.ToStringPercent()));
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 获取质量因子描述
|
||||
public string GetQualityFactorsDescription()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("ARA_EquipmentIncubator.QualityFactors".Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
// 1. 建筑血量损失百分比
|
||||
if (Ext.healthAffectsQuality)
|
||||
{
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
builder.AppendLine("ARA_EquipmentIncubator.BuildingHealth".Translate(healthPercent.ToStringPercent()));
|
||||
}
|
||||
|
||||
// 2. 房间质量因子
|
||||
if (Ext.useRoomQualityFactor)
|
||||
{
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
builder.AppendLine(roomFactor == 1.0f ?
|
||||
"ARA_EquipmentIncubator.RoomFactorNormal".Translate() :
|
||||
$"{(roomFactor > 1.0f ? "✓" : "✗")} {"ARA_EquipmentIncubator.RoomFactorModified".Translate()}{roomFactor.ToStringPercent()}");
|
||||
}
|
||||
|
||||
// 3. 附近其他卵
|
||||
int nearbyOothecaCount = CountNearbyOtherOothecas();
|
||||
if (nearbyOothecaCount > 0)
|
||||
{
|
||||
builder.AppendLine("ARA_EquipmentIncubator.NearbyOothecas".Translate(
|
||||
nearbyOothecaCount,
|
||||
Mathf.Min(nearbyOothecaCount * Ext.nearbyOothecaPenaltyPerUnit * 100, 100)));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine("ARA_EquipmentIncubator.NoNearbyOothecas".Translate());
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.OothecaDetectionRadius".Translate(Ext.nearbyOothecaRadius));
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.TotalQualityMultiplier".Translate(QualityMultiplier.ToStringPercent()));
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 构建呼叫幼虫描述
|
||||
private string BuildCallLarvaDescription(EquipmentIncubationConfig config)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("ARA_EquipmentIncubator.CallLarvaTitle".Translate());
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.LarvaWillCome".Translate());
|
||||
builder.AppendLine(config.thingDef.LabelCap);
|
||||
builder.AppendLine();
|
||||
|
||||
if (Ext.larvaSearchRadius < 999f)
|
||||
{
|
||||
builder.AppendLine("ARA_EquipmentIncubator.LarvaSearchRadius".Translate(Ext.larvaSearchRadius));
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 呼叫幼虫
|
||||
private void CallLarva()
|
||||
{
|
||||
if (isIncubating)
|
||||
{
|
||||
Messages.Message("ARA_EquipmentIncubator.AlreadyIncubating".Translate() + " " + "ARA_EquipmentIncubator.CancelFirst".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
|
||||
if (assignedLarva != null)
|
||||
{
|
||||
Messages.Message("ARA_EquipmentIncubator.LarvaAlreadyOnWay".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
|
||||
var larva = FindLarva();
|
||||
if (larva == null)
|
||||
{
|
||||
Messages.Message("ARA_EquipmentIncubator.NoLarvaeFound".Translate() + " " + "ARA_EquipmentIncubator.LarvaMustBeRace".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
|
||||
var job = JobMaker.MakeJob(ARA_JobDefOf.ARA_OperateEquipmentIncubator, this);
|
||||
job.count = 1;
|
||||
larva.jobs.TryTakeOrderedJob(job, JobTag.MiscWork);
|
||||
|
||||
assignedLarva = larva;
|
||||
|
||||
Messages.Message("ARA_EquipmentIncubator.LarvaCalled".Translate() + " " + "ARA_EquipmentIncubator.ArriveShortly".Translate(),
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
}
|
||||
|
||||
// 幼虫到达
|
||||
public void NotifyLarvaArrived(Pawn larva)
|
||||
{
|
||||
if (larva.def.defName != "ArachnaeBase_Race_Larva")
|
||||
{
|
||||
ArachnaeLog.Debug($"Invalid larva arrived: {larva.def.defName}");
|
||||
return;
|
||||
}
|
||||
|
||||
larvaOperateTicksRemaining = 180;
|
||||
assignedLarva = larva;
|
||||
|
||||
Messages.Message("ARA_EquipmentIncubator.LarvaArrived".Translate() + " " + "ARA_EquipmentIncubator.ActivatingOotheca".Translate(),
|
||||
MessageTypeDefOf.SilentInput);
|
||||
}
|
||||
|
||||
// 幼虫完成操作
|
||||
public void NotifyLarvaOperationComplete(Pawn larva)
|
||||
{
|
||||
if (larva != assignedLarva)
|
||||
{
|
||||
ArachnaeLog.Debug("Larva operation complete called with wrong larva.");
|
||||
return;
|
||||
}
|
||||
|
||||
var config = EquipmentIncubatorData?.SelectedConfig;
|
||||
if (config == null)
|
||||
{
|
||||
ArachnaeLog.Debug("No incubation config selected when larva completed operation.");
|
||||
return;
|
||||
}
|
||||
|
||||
incubatingThingDef = config.thingDef;
|
||||
incubationDuration = config.DaysRequired * 60000f;
|
||||
incubationProgress = 0f;
|
||||
isIncubating = true;
|
||||
|
||||
qualityTotal = incubationDuration;
|
||||
qualityProgress = 0f;
|
||||
UpdateQualityMultiplier();
|
||||
|
||||
UpdateSpeedMultiplier();
|
||||
|
||||
assignedLarva = null;
|
||||
larvaOperateTicksRemaining = 0;
|
||||
|
||||
Messages.Message("ARA_EquipmentIncubator.IncubationStarted".Translate() + " " + incubatingThingDef.LabelCap + ". " +
|
||||
"ARA_EquipmentIncubator.ProcessWillComplete".Translate() + " " + config.DaysRequired + " " + "ARA_EquipmentIncubator.DaysBaseTime".Translate(),
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
}
|
||||
|
||||
// 取消孵化
|
||||
private void CancelIncubation()
|
||||
{
|
||||
if (!isIncubating) return;
|
||||
|
||||
isIncubating = false;
|
||||
incubationProgress = 0f;
|
||||
incubationDuration = 0f;
|
||||
incubatingThingDef = null;
|
||||
qualityProgress = 0f;
|
||||
qualityTotal = 0f;
|
||||
|
||||
Messages.Message("ARA_EquipmentIncubator.IncubationCancelled".Translate() + " " + "ARA_EquipmentIncubator.ContentsLost".Translate(),
|
||||
MessageTypeDefOf.NeutralEvent);
|
||||
}
|
||||
|
||||
// 完成孵化
|
||||
private void CompleteIncubation()
|
||||
{
|
||||
if (incubatingThingDef == null) return;
|
||||
|
||||
float finalQualityPercent = QualityPercent;
|
||||
|
||||
// 生成物品
|
||||
Thing thing = ThingMaker.MakeThing(incubatingThingDef);
|
||||
|
||||
// 应用质量影响
|
||||
ApplyQualityEffects(thing, finalQualityPercent);
|
||||
|
||||
// 放置物品
|
||||
var spawnPos = Position;
|
||||
GenPlace.TryPlaceThing(thing, spawnPos, Map, ThingPlaceMode.Near);
|
||||
|
||||
// 重置状态
|
||||
isIncubating = false;
|
||||
incubationProgress = 0f;
|
||||
incubationDuration = 0f;
|
||||
incubatingThingDef = null;
|
||||
qualityProgress = 0f;
|
||||
qualityTotal = 0f;
|
||||
|
||||
// 显示消息
|
||||
string qualityText = finalQualityPercent >= 0.9f ? "ARA_EquipmentIncubator.QualityExcellent".Translate() :
|
||||
finalQualityPercent >= 0.7f ? "ARA_EquipmentIncubator.QualityGood".Translate() :
|
||||
finalQualityPercent >= 0.5f ? "ARA_EquipmentIncubator.QualityAverage".Translate() :
|
||||
finalQualityPercent >= 0.3f ? "ARA_EquipmentIncubator.QualityPoor".Translate() : "ARA_EquipmentIncubator.QualityVeryPoor".Translate();
|
||||
|
||||
Messages.Message("ARA_EquipmentIncubator.IncubationComplete".Translate() + " " + thing.LabelCap + " " +
|
||||
"ARA_EquipmentIncubator.HasEmergedWith".Translate() + " " + qualityText + " " +
|
||||
"ARA_EquipmentIncubator.Quality".Translate() + " (" + finalQualityPercent.ToStringPercent() + ").",
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// 应用质量效果
|
||||
private void ApplyQualityEffects(Thing thing, float qualityPercent)
|
||||
{
|
||||
// 应用质量效果到装备
|
||||
if (thing.TryGetComp<CompQuality>() is CompQuality compQuality)
|
||||
{
|
||||
// 根据质量百分比设置质量等级
|
||||
QualityCategory qualityCategory = qualityPercent >= 0.99f ? QualityCategory.Legendary :
|
||||
qualityPercent >= 0.75f ? QualityCategory.Masterwork :
|
||||
qualityPercent >= 0.6f ? QualityCategory.Excellent :
|
||||
qualityPercent >= 0.45f ? QualityCategory.Good :
|
||||
qualityPercent >= 0.3f ? QualityCategory.Normal : QualityCategory.Poor;
|
||||
|
||||
compQuality.SetQuality(qualityCategory, ArtGenerationContext.Outsider);
|
||||
}
|
||||
|
||||
// 设置生命值百分比
|
||||
if (qualityPercent < 1.0f)
|
||||
{
|
||||
float healthFactor = Mathf.Lerp(0.5f, 1.0f, qualityPercent);
|
||||
thing.HitPoints = Mathf.RoundToInt(thing.MaxHitPoints * healthFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取剩余时间
|
||||
public float GetRemainingTicks()
|
||||
{
|
||||
if (!isIncubating || incubationDuration <= incubationProgress) return 0f;
|
||||
|
||||
float remainingProgress = incubationDuration - incubationProgress;
|
||||
float currentSpeed = SpeedMultiplier;
|
||||
|
||||
if (currentSpeed <= 0) return float.MaxValue;
|
||||
|
||||
return remainingProgress / currentSpeed;
|
||||
}
|
||||
|
||||
public float GetRemainingDays()
|
||||
{
|
||||
return GetRemainingTicks() / 60000f;
|
||||
}
|
||||
|
||||
public float GetRemainingHours()
|
||||
{
|
||||
float remainingTicks = GetRemainingTicks();
|
||||
return (remainingTicks % 60000f) / 2500f;
|
||||
}
|
||||
|
||||
// 检查字符串
|
||||
public override string GetInspectString()
|
||||
{
|
||||
var baseString = base.GetInspectString();
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (!string.IsNullOrEmpty(baseString))
|
||||
{
|
||||
builder.Append(baseString);
|
||||
}
|
||||
|
||||
if (isIncubating && incubatingThingDef != null)
|
||||
{
|
||||
float progressPercent = AdjustedProgressPercent;
|
||||
float daysRemaining = GetRemainingDays();
|
||||
float hoursRemaining = GetRemainingHours();
|
||||
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("ARA_EquipmentIncubator.Incubating".Translate() + ": " + incubatingThingDef.LabelCap);
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_EquipmentIncubator.Progress".Translate() + ": " + progressPercent.ToStringPercent());
|
||||
builder.AppendLine();
|
||||
|
||||
string timeText = "ARA_EquipmentIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.Hours".Translate() + ")";
|
||||
}
|
||||
builder.Append(timeText);
|
||||
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_EquipmentIncubator.Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_EquipmentIncubator.Quality".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
else if (assignedLarva != null)
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
if (larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = larvaOperateTicksRemaining / 60f;
|
||||
builder.Append("ARA_EquipmentIncubator.LarvaOperating".Translate() + ": " + secondsRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.SRemaining".Translate());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("ARA_EquipmentIncubator.LarvaOnWay".Translate());
|
||||
}
|
||||
}
|
||||
else if (!isIncubating)
|
||||
{
|
||||
var config = EquipmentIncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("ARA_EquipmentIncubator.Target".Translate() + ": " + config.thingDef.LabelCap);
|
||||
|
||||
builder.AppendLine();
|
||||
builder.Append("ARA_EquipmentIncubator.SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_EquipmentIncubator.QualityMultiplier".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// Gizmos
|
||||
public override IEnumerable<Gizmo> GetGizmos()
|
||||
{
|
||||
foreach (var gizmo in base.GetGizmos())
|
||||
{
|
||||
yield return gizmo;
|
||||
}
|
||||
|
||||
if (Faction == Faction.OfPlayer)
|
||||
{
|
||||
if (!isIncubating && EquipmentIncubatorData?.IncubationConfigs?.Count > 0)
|
||||
{
|
||||
yield return CreateTargetSwitchGizmo();
|
||||
}
|
||||
|
||||
var config = EquipmentIncubatorData?.SelectedConfig;
|
||||
if (!isIncubating && config != null && config.IsResearchComplete)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "ARA_EquipmentIncubator.CallLarva".Translate(),
|
||||
defaultDesc = BuildCallLarvaDescription(config),
|
||||
icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false) ?? BaseContent.BadTex,
|
||||
action = CallLarva,
|
||||
hotKey = KeyBindingDefOf.Misc3
|
||||
};
|
||||
}
|
||||
|
||||
if (isIncubating)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "ARA_EquipmentIncubator.CancelIncubation".Translate(),
|
||||
defaultDesc = "ARA_EquipmentIncubator.CancelIncubationDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Cancel", false) ?? TexCommand.ClearPrioritizedWork,
|
||||
action = CancelIncubation
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建切换目标Gizmo - 现在使用装备的图标
|
||||
private Gizmo CreateTargetSwitchGizmo()
|
||||
{
|
||||
var configs = EquipmentIncubatorData?.IncubationConfigs;
|
||||
if (configs == null || configs.Count == 0) return null;
|
||||
|
||||
var props = EquipmentIncubatorData?.props as CompProperties_EquipmentIncubatorData;
|
||||
var selectedConfig = EquipmentIncubatorData?.SelectedConfig;
|
||||
|
||||
var switchButton = new Command_Action
|
||||
{
|
||||
defaultLabel = BuildSwitchButtonLabel(selectedConfig, props),
|
||||
defaultDesc = BuildSwitchButtonDescription(selectedConfig, props),
|
||||
icon = GetConfigIcon(selectedConfig),
|
||||
action = ShowSelectionMenu,
|
||||
hotKey = KeyBindingDefOf.Misc2
|
||||
};
|
||||
|
||||
if (selectedConfig != null && !selectedConfig.IsResearchComplete)
|
||||
{
|
||||
if (selectedConfig.requiredResearch != null)
|
||||
{
|
||||
switchButton.Disable($"Requires research: {selectedConfig.requiredResearch.LabelCap}");
|
||||
}
|
||||
}
|
||||
|
||||
return switchButton;
|
||||
}
|
||||
|
||||
// 获取配置图标 - 现在直接从ThingDef获取
|
||||
private Texture2D GetConfigIcon(EquipmentIncubationConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
return BaseContent.BadTex;
|
||||
|
||||
// 如果配置中没有缓存图标,尝试直接获取ThingDef的uiIcon
|
||||
if (config.thingDef?.uiIcon != null)
|
||||
return config.thingDef.uiIcon;
|
||||
|
||||
// 回退到默认图标
|
||||
return ContentFinder<Texture2D>.Get("UI/Commands/Default", false) ?? BaseContent.BadTex;
|
||||
}
|
||||
|
||||
private string BuildSwitchButtonLabel(EquipmentIncubationConfig config, CompProperties_EquipmentIncubatorData props)
|
||||
{
|
||||
if (config != null && config.thingDef != null)
|
||||
{
|
||||
return (props?.buttonLabel ?? "ARA_EquipmentIncubator.IncubateLabel").Translate(config.thingDef.LabelCap);
|
||||
}
|
||||
return (props?.buttonLabel ?? "ARA_EquipmentIncubator.IncubateLabel").Translate("None");
|
||||
}
|
||||
|
||||
private string BuildSwitchButtonDescription(EquipmentIncubationConfig config, CompProperties_EquipmentIncubatorData props)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine((props?.buttonDesc ?? "ARA_EquipmentIncubator.ButtonDesc").Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
if (config.thingDef != null)
|
||||
{
|
||||
builder.AppendLine($"ARA_EquipmentIncubator.ButtonLabel".Translate(config.thingDef.LabelCap));
|
||||
if (!string.IsNullOrEmpty(config.thingDef.description))
|
||||
{
|
||||
builder.AppendLine(config.thingDef.description);
|
||||
}
|
||||
}
|
||||
|
||||
builder.AppendLine($"ARA_EquipmentIncubator.IncubationTime".Translate(config.DaysRequired));
|
||||
|
||||
if (config.requiredResearch != null)
|
||||
{
|
||||
if (config.requiredResearch.IsFinished)
|
||||
builder.AppendLine($"Research: {config.requiredResearch.LabelCap} (Completed)");
|
||||
else
|
||||
builder.AppendLine($"Research: {config.requiredResearch.LabelCap} (Required)");
|
||||
}
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.ButtonDesc".Translate());
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
private void ShowSelectionMenu()
|
||||
{
|
||||
var configs = EquipmentIncubatorData?.IncubationConfigs;
|
||||
var props = EquipmentIncubatorData?.props as CompProperties_EquipmentIncubatorData;
|
||||
if (configs == null || configs.Count == 0) return;
|
||||
|
||||
var options = new List<FloatMenuOption>();
|
||||
int currentIndex = EquipmentIncubatorData.GetSelectedIndex();
|
||||
|
||||
for (int i = 0; i < configs.Count; i++)
|
||||
{
|
||||
int index = i;
|
||||
var config = configs[i];
|
||||
if (config == null || config.thingDef == null) continue;
|
||||
|
||||
string label = config.thingDef.LabelCap;
|
||||
string description = config.GetDescription();
|
||||
|
||||
string prefix = (i == currentIndex) ? "✓ " : " ";
|
||||
|
||||
// 使用原版FloatMenuOption的构造函数,直接传入图标
|
||||
FloatMenuOption option;
|
||||
|
||||
// 尝试获取ThingDef的图标
|
||||
Texture2D icon = config.thingDef.uiIcon;
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
// 使用带有Texture2D图标的构造函数
|
||||
option = new FloatMenuOption(
|
||||
prefix + label,
|
||||
() => SwitchToConfig(index),
|
||||
icon,
|
||||
Color.white,
|
||||
MenuOptionPriority.Default,
|
||||
null, // mouseoverGuiAction
|
||||
null, // revalidateClickTarget
|
||||
0f, // extraPartWidth
|
||||
null, // extraPartOnGUI
|
||||
null, // revalidateWorldClickTarget
|
||||
true, // playSelectionSound
|
||||
0, // orderInPriority
|
||||
HorizontalJustification.Left, // iconJustification
|
||||
false // extraPartRightJustified
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有图标,使用普通构造函数
|
||||
option = new FloatMenuOption(
|
||||
prefix + label,
|
||||
() => SwitchToConfig(index)
|
||||
);
|
||||
}
|
||||
|
||||
// 设置工具提示
|
||||
option.tooltip = description;
|
||||
|
||||
// 如果研究未完成,禁用选项
|
||||
if (!config.IsResearchComplete)
|
||||
{
|
||||
option.Label = prefix + label;
|
||||
option.Disabled = true;
|
||||
option.tooltip = description + "\n\n " + "ARA_EquipmentIncubator.ResearchRequired".Translate() + " " + config.requiredResearch.LabelCap;
|
||||
}
|
||||
|
||||
options.Add(option);
|
||||
}
|
||||
|
||||
if (options.Count > 0)
|
||||
{
|
||||
Find.WindowStack.Add(new FloatMenu(options,
|
||||
(props?.menuTitle ?? "ARA_EquipmentIncubator.MenuTitle").Translate()));
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchToConfig(int index)
|
||||
{
|
||||
if (EquipmentIncubatorData != null)
|
||||
{
|
||||
EquipmentIncubatorData.SwitchToConfig(index);
|
||||
var config = EquipmentIncubatorData.SelectedConfig;
|
||||
if (config != null && config.thingDef != null)
|
||||
{
|
||||
Messages.Message($"ARA_EquipmentIncubator.TargetSwitched".Translate(config.thingDef.LabelCap),
|
||||
this, MessageTypeDefOf.SilentInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找幼虫
|
||||
private Pawn FindLarva()
|
||||
{
|
||||
var map = Map;
|
||||
if (map == null) return null;
|
||||
|
||||
float searchRadius = Ext.larvaSearchRadius;
|
||||
|
||||
foreach (var pawn in map.mapPawns.SpawnedPawnsInFaction(Faction))
|
||||
{
|
||||
if (pawn.def.defName == "ArachnaeBase_Race_Larva")
|
||||
{
|
||||
if (searchRadius < 999f)
|
||||
{
|
||||
float distance = pawn.Position.DistanceTo(Position);
|
||||
if (distance > searchRadius)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pawn.Downed && !pawn.InMentalState &&
|
||||
pawn.mindState != null &&
|
||||
(pawn.CurJob == null || pawn.CurJob.def != ARA_JobDefOf.ARA_OperateEquipmentIncubator))
|
||||
{
|
||||
return pawn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 每tick更新
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
|
||||
if (larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
larvaOperateTicksRemaining--;
|
||||
}
|
||||
|
||||
if (isIncubating)
|
||||
{
|
||||
if (lastMultiplierUpdateTick < 0 || Find.TickManager.TicksGame - lastMultiplierUpdateTick >= MultiplierUpdateInterval)
|
||||
{
|
||||
UpdateSpeedMultiplier();
|
||||
UpdateQualityMultiplier();
|
||||
}
|
||||
|
||||
float currentSpeed = SpeedMultiplier;
|
||||
incubationProgress += currentSpeed;
|
||||
|
||||
qualityProgress += currentSpeed * QualityMultiplier;
|
||||
|
||||
if (incubationProgress >= incubationDuration)
|
||||
{
|
||||
CompleteIncubation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否在孵化间中
|
||||
private bool IsInIncubatorRoom()
|
||||
{
|
||||
if (!Ext.requiresIncubatorRoom)
|
||||
return true;
|
||||
|
||||
var room = this.GetRoom();
|
||||
if (room == null) return false;
|
||||
|
||||
return room.Role != null && room.Role.defName == "ARA_Incubator_Room";
|
||||
}
|
||||
|
||||
// 计算营养液数量
|
||||
private int CountNearbyNutrientSolutions()
|
||||
{
|
||||
var map = Map;
|
||||
if (map == null) return 0;
|
||||
|
||||
int count = 0;
|
||||
int radius = Ext.NutrientSolutionRadiusInt;
|
||||
|
||||
for (int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
{
|
||||
IntVec3 cell = Position + new IntVec3(x, 0, y);
|
||||
|
||||
if (cell.InBounds(map))
|
||||
{
|
||||
TerrainDef terrain = map.terrainGrid.TerrainAt(cell);
|
||||
if (terrain != null && terrain.defName == "ARA_Incubator_Nutrient_Solution")
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// 计算房间质量因子
|
||||
private float GetRoomQualityFactor()
|
||||
{
|
||||
if (!Ext.useRoomQualityFactor)
|
||||
return 1.0f;
|
||||
|
||||
var room = this.GetRoom();
|
||||
if (room == null) return 1.0f;
|
||||
|
||||
var statDef = DefDatabase<RoomStatDef>.GetNamedSilentFail("ARA_IncubatorQualityFactor");
|
||||
if (statDef != null)
|
||||
{
|
||||
return room.GetStat(statDef);
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// 计算附近其他卵的数量
|
||||
private int CountNearbyOtherOothecas()
|
||||
{
|
||||
var map = Map;
|
||||
if (map == null) return 0;
|
||||
|
||||
int count = 0;
|
||||
var allBuildings = map.listerThings.ThingsOfDef(this.def);
|
||||
|
||||
foreach (var building in allBuildings)
|
||||
{
|
||||
if (building == this) continue;
|
||||
|
||||
if (building.def.defName == "ARA_Pawn_Ootheca" || building.def.defName == "ARA_Equipment_Ootheca")
|
||||
{
|
||||
bool isNearby = false;
|
||||
|
||||
if (Ext.checkSameRoomForOotheca)
|
||||
{
|
||||
var room = building.GetRoom();
|
||||
if (room != null && room == this.GetRoom())
|
||||
{
|
||||
isNearby = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNearby)
|
||||
{
|
||||
float distance = building.Position.DistanceTo(this.Position);
|
||||
if (distance <= Ext.nearbyOothecaRadius)
|
||||
{
|
||||
isNearby = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNearby)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// 更新速度乘数
|
||||
private void UpdateSpeedMultiplier()
|
||||
{
|
||||
float multiplier = 1.0f;
|
||||
|
||||
if (Ext.requiresIncubatorRoom && !IsInIncubatorRoom())
|
||||
{
|
||||
multiplier *= Ext.speedPenaltyOutsideIncubator;
|
||||
}
|
||||
|
||||
int nutrientSolutionCount = CountNearbyNutrientSolutions();
|
||||
float nutrientBonus = 1.0f + (nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile);
|
||||
|
||||
multiplier *= nutrientBonus;
|
||||
|
||||
speedMultiplier = multiplier;
|
||||
lastMultiplierUpdateTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
|
||||
// 更新质量乘数
|
||||
private void UpdateQualityMultiplier()
|
||||
{
|
||||
float multiplier = 1.0f;
|
||||
|
||||
if (Ext.healthAffectsQuality)
|
||||
{
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
multiplier *= healthPercent;
|
||||
}
|
||||
|
||||
if (Ext.useRoomQualityFactor)
|
||||
{
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
multiplier *= roomFactor;
|
||||
}
|
||||
|
||||
int nearbyOothecaCount = CountNearbyOtherOothecas();
|
||||
float oothecaPenalty = Mathf.Max(0f, 1.0f - (nearbyOothecaCount * Ext.nearbyOothecaPenaltyPerUnit));
|
||||
multiplier *= oothecaPenalty;
|
||||
|
||||
qualityMultiplier = Mathf.Clamp(multiplier, 0f, 1.0f);
|
||||
}
|
||||
|
||||
// 保存/加载
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Values.Look(ref isIncubating, "isIncubating", false);
|
||||
Scribe_Values.Look(ref incubationProgress, "incubationProgress", 0f);
|
||||
Scribe_Values.Look(ref incubationDuration, "incubationDuration", 0f);
|
||||
Scribe_Defs.Look(ref incubatingThingDef, "incubatingThingDef");
|
||||
Scribe_References.Look(ref assignedLarva, "assignedLarva");
|
||||
Scribe_Values.Look(ref larvaOperateTicksRemaining, "larvaOperateTicksRemaining", 0);
|
||||
Scribe_Values.Look(ref speedMultiplier, "speedMultiplier", 1.0f);
|
||||
Scribe_Values.Look(ref lastMultiplierUpdateTick, "lastMultiplierUpdateTick", -1);
|
||||
Scribe_Values.Look(ref qualityMultiplier, "qualityMultiplier", 1.0f);
|
||||
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
|
||||
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
// File: Comps/CompProperties_EquipmentIncubatorData.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
// 装备孵化配置
|
||||
public class EquipmentIncubationConfig : IExposable
|
||||
{
|
||||
public ThingDef thingDef;
|
||||
public ResearchProjectDef requiredResearch;
|
||||
public float daysRequired; // 从stat中读取
|
||||
public string buttonIconPath;
|
||||
|
||||
// 缓存的生产时间(避免重复获取stat)
|
||||
private float? cachedDaysRequired;
|
||||
|
||||
public EquipmentIncubationConfig() { }
|
||||
|
||||
public EquipmentIncubationConfig(ThingDef thingDef, ResearchProjectDef requiredResearch = null,
|
||||
string buttonIconPath = null)
|
||||
{
|
||||
this.thingDef = thingDef;
|
||||
this.requiredResearch = requiredResearch;
|
||||
this.buttonIconPath = buttonIconPath;
|
||||
cachedDaysRequired = null;
|
||||
}
|
||||
|
||||
public void ExposeData()
|
||||
{
|
||||
Scribe_Defs.Look(ref thingDef, "thingDef");
|
||||
Scribe_Defs.Look(ref requiredResearch, "requiredResearch");
|
||||
Scribe_Values.Look(ref buttonIconPath, "buttonIconPath");
|
||||
|
||||
// 不保存缓存值,重新计算
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
cachedDaysRequired = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取生产时间(天)
|
||||
public float DaysRequired
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedDaysRequired.HasValue)
|
||||
return cachedDaysRequired.Value;
|
||||
|
||||
if (thingDef == null)
|
||||
{
|
||||
cachedDaysRequired = 1f;
|
||||
return cachedDaysRequired.Value;
|
||||
}
|
||||
|
||||
// 从stat中读取ARA_IncubationTime
|
||||
var statDef = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationTime");
|
||||
if (statDef != null)
|
||||
{
|
||||
cachedDaysRequired = thingDef.GetStatValueAbstract(statDef, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 默认值
|
||||
cachedDaysRequired = 1f;
|
||||
}
|
||||
|
||||
return cachedDaysRequired.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否满足研究要求
|
||||
public bool IsResearchComplete => requiredResearch == null || requiredResearch.IsFinished;
|
||||
|
||||
// 获取描述
|
||||
public string GetDescription()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (thingDef != null)
|
||||
{
|
||||
builder.AppendLine(thingDef.description ?? "ARA_EquipmentIncubator.NoDescription".Translate());
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_EquipmentIncubator.IncubationTime".Translate(DaysRequired));
|
||||
}
|
||||
|
||||
if (requiredResearch != null)
|
||||
{
|
||||
if (requiredResearch.IsFinished)
|
||||
builder.AppendLine("ARA_EquipmentIncubator.ResearchCompleted".Translate(requiredResearch.LabelCap));
|
||||
else
|
||||
builder.AppendLine("ARA_EquipmentIncubator.ResearchRequired".Translate(requiredResearch.LabelCap));
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
}
|
||||
|
||||
// 装备孵化器组件属性
|
||||
public class CompProperties_EquipmentIncubatorData : CompProperties
|
||||
{
|
||||
// 支持手动指定配置列表(可选)
|
||||
public List<EquipmentIncubationConfig> incubationConfigs;
|
||||
|
||||
// 默认选择索引
|
||||
public int defaultIndex = 0;
|
||||
|
||||
// Gizmo相关配置
|
||||
public string buttonLabel = "ARA_EquipmentIncubator.IncubateLabel";
|
||||
public string buttonDesc = "ARA_EquipmentIncubator.ButtonDesc";
|
||||
public string menuTitle = "ARA_EquipmentIncubator.MenuTitle";
|
||||
public string defaultIconPath = "UI/Commands/Default";
|
||||
|
||||
// 是否自动扫描所有ThingDef来构建配置列表
|
||||
public bool autoScanThingDefs = true;
|
||||
|
||||
// 手动指定要扫描的ThingDef类型(可选)
|
||||
public List<string> thingDefCategories;
|
||||
public List<ThingCategoryDef> thingCategoryDefs;
|
||||
|
||||
public CompProperties_EquipmentIncubatorData()
|
||||
{
|
||||
compClass = typeof(CompEquipmentIncubatorData);
|
||||
}
|
||||
}
|
||||
|
||||
// 装备孵化器数据组件
|
||||
public class CompEquipmentIncubatorData : ThingComp
|
||||
{
|
||||
private CompProperties_EquipmentIncubatorData Props => (CompProperties_EquipmentIncubatorData)props;
|
||||
|
||||
// 当前选择的配置索引
|
||||
private int selectedIndex = -1;
|
||||
|
||||
// 缓存的配置列表
|
||||
private List<EquipmentIncubationConfig> cachedConfigs;
|
||||
private bool configsBuilt = false;
|
||||
|
||||
// 公开获取孵化配置列表的方法
|
||||
public List<EquipmentIncubationConfig> IncubationConfigs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!configsBuilt)
|
||||
{
|
||||
BuildIncubationConfigs();
|
||||
}
|
||||
return cachedConfigs ?? new List<EquipmentIncubationConfig>();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前选择的配置
|
||||
public EquipmentIncubationConfig SelectedConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
var configs = IncubationConfigs;
|
||||
if (configs.Count == 0) return null;
|
||||
|
||||
// 初始化选择
|
||||
if (selectedIndex == -1)
|
||||
{
|
||||
selectedIndex = Mathf.Clamp(Props.defaultIndex, 0, configs.Count - 1);
|
||||
}
|
||||
|
||||
if (selectedIndex < 0 || selectedIndex >= configs.Count)
|
||||
selectedIndex = 0;
|
||||
|
||||
return configs[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前选择的ThingDef
|
||||
public ThingDef SelectedThingDef => SelectedConfig?.thingDef;
|
||||
|
||||
// 构建孵化配置列表
|
||||
private void BuildIncubationConfigs()
|
||||
{
|
||||
cachedConfigs = new List<EquipmentIncubationConfig>();
|
||||
configsBuilt = true;
|
||||
|
||||
// 优先使用手动配置的列表
|
||||
if (Props.incubationConfigs != null && Props.incubationConfigs.Count > 0)
|
||||
{
|
||||
foreach (var config in Props.incubationConfigs)
|
||||
{
|
||||
if (config?.thingDef != null)
|
||||
{
|
||||
cachedConfigs.Add(config);
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedConfigs.Count > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有手动配置,且启用了自动扫描,则扫描所有ThingDef
|
||||
if (Props.autoScanThingDefs)
|
||||
{
|
||||
ScanThingDefsForConfigs();
|
||||
}
|
||||
}
|
||||
|
||||
// 扫描所有ThingDef来构建配置列表
|
||||
private void ScanThingDefsForConfigs()
|
||||
{
|
||||
var allThingDefs = DefDatabase<ThingDef>.AllDefsListForReading;
|
||||
|
||||
foreach (var thingDef in allThingDefs)
|
||||
{
|
||||
// 检查该ThingDef是否包含CompProperties_ExtraIncubationInfo组件
|
||||
var extraInfoProps = thingDef.comps?.FirstOrDefault(c => c is CompProperties_ExtraIncubationInfo)
|
||||
as CompProperties_ExtraIncubationInfo;
|
||||
|
||||
if (extraInfoProps == null)
|
||||
continue;
|
||||
|
||||
// 检查cocoonDefs是否包含当前建筑
|
||||
bool isForThisCocoon = false;
|
||||
|
||||
if (extraInfoProps.cocoonDefs != null && extraInfoProps.cocoonDefs.Count > 0)
|
||||
{
|
||||
isForThisCocoon = extraInfoProps.cocoonDefs.Contains(parent.def);
|
||||
}
|
||||
else if (extraInfoProps.cocoonDef != null)
|
||||
{
|
||||
// 向后兼容:检查单个cocoonDef
|
||||
isForThisCocoon = extraInfoProps.cocoonDef == parent.def;
|
||||
}
|
||||
|
||||
if (!isForThisCocoon)
|
||||
continue;
|
||||
|
||||
// 检查是否有ARA_IncubationTime这个stat
|
||||
var incubationTimeStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationTime");
|
||||
if (incubationTimeStat == null)
|
||||
{
|
||||
Log.Warning($"ThingDef {thingDef.defName} has CompProperties_ExtraIncubationInfo but ARA_IncubationTime stat is not defined.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取孵化时间
|
||||
float daysRequired = thingDef.GetStatValueAbstract(incubationTimeStat, null);
|
||||
if (daysRequired <= 0)
|
||||
{
|
||||
Log.Warning($"ThingDef {thingDef.defName} has invalid incubation time: {daysRequired}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建配置
|
||||
var config = new EquipmentIncubationConfig
|
||||
{
|
||||
thingDef = thingDef,
|
||||
daysRequired = daysRequired,
|
||||
// 可以在这里添加其他配置,比如所需研究等
|
||||
// requiredResearch = ...
|
||||
// buttonIconPath = ...
|
||||
};
|
||||
|
||||
cachedConfigs.Add(config);
|
||||
}
|
||||
|
||||
// 按物品名称排序
|
||||
cachedConfigs.Sort((a, b) => string.Compare(a.thingDef?.label ?? "", b.thingDef?.label ?? ""));
|
||||
|
||||
Log.Message($"Built {cachedConfigs.Count} equipment incubation configs for {parent.def.defName}");
|
||||
}
|
||||
|
||||
// 切换到特定索引
|
||||
public void SwitchToConfig(int index)
|
||||
{
|
||||
if (index >= 0 && index < IncubationConfigs.Count)
|
||||
{
|
||||
selectedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查配置是否可用(研究是否完成)
|
||||
public bool IsConfigAvailable(int index)
|
||||
{
|
||||
if (index < 0 || index >= IncubationConfigs.Count)
|
||||
return false;
|
||||
|
||||
var config = IncubationConfigs[index];
|
||||
return config?.IsResearchComplete ?? false;
|
||||
}
|
||||
|
||||
// 获取配置索引
|
||||
public int GetSelectedIndex()
|
||||
{
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
// 存档加载
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref selectedIndex, "selectedIndex", -1);
|
||||
Scribe_Values.Look(ref configsBuilt, "configsBuilt", false);
|
||||
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
// 重置缓存,在需要时重新构建
|
||||
cachedConfigs = null;
|
||||
configsBuilt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 在建筑信息中显示额外信息
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
var current = SelectedConfig;
|
||||
if (current != null && current.thingDef != null)
|
||||
{
|
||||
string status = "ARA_EquipmentIncubator.IncubationTarget".Translate(current.thingDef.LabelCap);
|
||||
|
||||
if (current.requiredResearch != null && !current.requiredResearch.IsFinished)
|
||||
{
|
||||
status += " (" + "ARA_EquipmentIncubator.Requires".Translate() + ": " + current.requiredResearch.LabelCap + ")";
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
return base.CompInspectStringExtra();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// File: ITabs/ITab_EquipmentOotheca_Incubation.cs
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class ITab_EquipmentOotheca_Incubation : ITab
|
||||
{
|
||||
private const float BarHeight = 20f;
|
||||
private const float Margin = 10f;
|
||||
private const float LabelHeight = 30f;
|
||||
private const float SmallLabelHeight = 20f;
|
||||
private const float ButtonHeight = 25f;
|
||||
private const float TabWidth = 320f;
|
||||
private const float TabHeight = 420f;
|
||||
|
||||
private Vector2 scrollPosition = Vector2.zero;
|
||||
private const float ViewHeight = 450f;
|
||||
|
||||
public override bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelThing.Faction == Faction.OfPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public ITab_EquipmentOotheca_Incubation()
|
||||
{
|
||||
size = new Vector2(TabWidth, TabHeight);
|
||||
labelKey = "ARA_EquipmentIncubator.IncubationTab";
|
||||
tutorTag = "EquipmentIncubation";
|
||||
}
|
||||
|
||||
protected override void FillTab()
|
||||
{
|
||||
Rect rect = new Rect(0f, 0f, size.x, size.y).ContractedBy(Margin);
|
||||
Widgets.DrawMenuSection(rect);
|
||||
Building_EquipmentOotheca ootheca = SelThing as Building_EquipmentOotheca;
|
||||
if (ootheca == null)
|
||||
{
|
||||
Widgets.Label(rect, "ARA_EquipmentIncubator.NotAnEquipmentOotheca".Translate());
|
||||
return;
|
||||
}
|
||||
rect = rect.ContractedBy(5f);
|
||||
|
||||
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, ViewHeight);
|
||||
Rect scrollRect = new Rect(rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
Widgets.BeginScrollView(scrollRect, ref scrollPosition, viewRect);
|
||||
|
||||
float curY = 0f;
|
||||
|
||||
Rect titleRect = new Rect(0f, curY, viewRect.width, LabelHeight);
|
||||
string title = "ARA_EquipmentIncubator.IncubationProgress".Translate();
|
||||
Text.Font = GameFont.Medium;
|
||||
Widgets.Label(titleRect, title);
|
||||
Text.Font = GameFont.Small;
|
||||
curY += LabelHeight + 15f;
|
||||
|
||||
float buttonWidth = (viewRect.width - 10f) / 2f;
|
||||
|
||||
Rect speedButtonRect = new Rect(0f, curY, buttonWidth, ButtonHeight);
|
||||
string speedText = "ARA_EquipmentIncubator.Speed".Translate() + ": " + ootheca.SpeedMultiplier.ToStringPercent();
|
||||
|
||||
Color speedColor = Color.white;
|
||||
if (ootheca.SpeedMultiplier != 1.0f)
|
||||
{
|
||||
speedColor = ootheca.SpeedMultiplier > 1.0f ?
|
||||
new Color(0.2f, 0.8f, 0.2f) :
|
||||
new Color(0.8f, 0.8f, 0.2f);
|
||||
}
|
||||
|
||||
if (Widgets.ButtonText(speedButtonRect, speedText, true, true, speedColor))
|
||||
{
|
||||
// 可选:显示详细信息
|
||||
}
|
||||
|
||||
TooltipHandler.TipRegion(speedButtonRect, () => ootheca.GetSpeedFactorsDescription(), 987654321);
|
||||
|
||||
Rect qualityButtonRect = new Rect(buttonWidth + 10f, curY, buttonWidth, ButtonHeight);
|
||||
string qualityText = "ARA_EquipmentIncubator.Quality".Translate() + ": " + ootheca.QualityMultiplier.ToStringPercent();
|
||||
|
||||
Color qualityColor = Color.white;
|
||||
float qualityMultiplier = ootheca.QualityMultiplier;
|
||||
if (qualityMultiplier != 1.0f)
|
||||
{
|
||||
if (qualityMultiplier > 0.9f)
|
||||
qualityColor = new Color(0.2f, 0.8f, 0.2f);
|
||||
else if (qualityMultiplier > 0.7f)
|
||||
qualityColor = new Color(0.8f, 0.8f, 0.2f);
|
||||
else if (qualityMultiplier > 0.5f)
|
||||
qualityColor = new Color(0.9f, 0.6f, 0.2f);
|
||||
else
|
||||
qualityColor = new Color(0.8f, 0.2f, 0.2f);
|
||||
}
|
||||
|
||||
if (Widgets.ButtonText(qualityButtonRect, qualityText, true, true, qualityColor))
|
||||
{
|
||||
// 可选:显示详细信息
|
||||
}
|
||||
|
||||
TooltipHandler.TipRegion(qualityButtonRect, () => ootheca.GetQualityFactorsDescription(), 987654322);
|
||||
|
||||
curY += ButtonHeight + 25f;
|
||||
|
||||
if (ootheca.isIncubating && ootheca.incubatingThingDef != null)
|
||||
{
|
||||
float progressPercent = ootheca.AdjustedProgressPercent;
|
||||
float qualityPercent = ootheca.QualityPercent;
|
||||
float daysRemaining = ootheca.GetRemainingDays();
|
||||
float hoursRemaining = ootheca.GetRemainingHours();
|
||||
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(targetRect, "ARA_EquipmentIncubator.Target".Translate() + ": " + ootheca.incubatingThingDef.LabelCap);
|
||||
curY += SmallLabelHeight + 20f;
|
||||
|
||||
Rect progressBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
Rect progressLabelRect = new Rect(progressBarRect.x, progressBarRect.y - 20, progressBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
Widgets.Label(progressLabelRect, "ARA_EquipmentIncubator.IncubationProgressLabel".Translate());
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
Widgets.FillableBar(progressBarRect, progressPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.2f, 0.5f)));
|
||||
Widgets.FillableBarChangeArrows(progressBarRect, progressPercent);
|
||||
|
||||
string progressText = $"{progressPercent:P0}";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(progressBarRect, progressText);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
curY += BarHeight + 30f;
|
||||
|
||||
Rect qualityBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
Rect qualityLabelRect = new Rect(qualityBarRect.x, qualityBarRect.y - 20, qualityBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
GUI.color = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
Widgets.Label(qualityLabelRect, "ARA_EquipmentIncubator.QualityProgress".Translate());
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
Widgets.FillableBar(qualityBarRect, qualityPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.4f, 0.8f, 0.5f)));
|
||||
|
||||
string qualityProgressText = $"{qualityPercent:P0}";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(qualityBarRect, qualityProgressText);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
Rect targetQualityRect = new Rect(qualityBarRect.x + qualityBarRect.width - 40, qualityBarRect.y, 40, BarHeight);
|
||||
GUI.color = new Color(0.8f, 0.8f, 0.8f, 0.7f);
|
||||
Text.Anchor = TextAnchor.MiddleRight;
|
||||
Widgets.Label(targetQualityRect, $"{ootheca.QualityMultiplier:P0}");
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
curY += BarHeight + 25f;
|
||||
|
||||
Rect timeRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
string timeText = "ARA_EquipmentIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.Hours".Translate() + ")";
|
||||
}
|
||||
Widgets.Label(timeRect, timeText);
|
||||
}
|
||||
else if (ootheca.assignedLarva != null)
|
||||
{
|
||||
Rect statusRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 2);
|
||||
if (ootheca.larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = ootheca.larvaOperateTicksRemaining / 60f;
|
||||
Widgets.Label(statusRect, "ARA_EquipmentIncubator.LarvaIsActivatingOotheca".Translate() + "\n" +
|
||||
secondsRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.SecondsRemaining".Translate());
|
||||
}
|
||||
else
|
||||
{
|
||||
Widgets.Label(statusRect, "ARA_EquipmentIncubator.LarvaIsOnTheWay".Translate());
|
||||
}
|
||||
|
||||
curY += SmallLabelHeight * 2 + 15f;
|
||||
|
||||
var config = ootheca.EquipmentIncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
curY += 10f;
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 3);
|
||||
string targetText = "ARA_EquipmentIncubator.ReadyToIncubate".Translate() + "\n" + config.thingDef.LabelCap;
|
||||
|
||||
if (!config.IsResearchComplete && config.requiredResearch != null)
|
||||
{
|
||||
targetText += "\n" + "(" + "ARA_EquipmentIncubator.Requires".Translate() + ": " + config.requiredResearch.LabelCap + ")";
|
||||
}
|
||||
|
||||
Widgets.Label(targetRect, targetText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var config = ootheca.EquipmentIncubatorData?.SelectedConfig;
|
||||
if (config != null)
|
||||
{
|
||||
Rect targetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 3);
|
||||
string targetText = "ARA_EquipmentIncubator.ReadyToIncubate".Translate() + "\n" + config.thingDef.LabelCap;
|
||||
|
||||
if (!config.IsResearchComplete && config.requiredResearch != null)
|
||||
{
|
||||
targetText += "\n" + "(" + "ARA_EquipmentIncubator.Requires".Translate() + ": " + config.requiredResearch.LabelCap + ")";
|
||||
}
|
||||
|
||||
Widgets.Label(targetRect, targetText);
|
||||
curY += SmallLabelHeight * 3 + 10f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect noTargetRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(noTargetRect, "ARA_EquipmentIncubator.NoIncubationTargetSelected".Translate());
|
||||
curY += SmallLabelHeight + 10f;
|
||||
}
|
||||
}
|
||||
|
||||
curY += 20f;
|
||||
viewRect.height = curY;
|
||||
|
||||
Widgets.EndScrollView();
|
||||
}
|
||||
|
||||
protected override void UpdateSize()
|
||||
{
|
||||
size = new Vector2(TabWidth, TabHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// File: JobDrivers/JobDriver_OperateEquipmentIncubator.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_OperateEquipmentIncubator : JobDriver
|
||||
{
|
||||
private const int OperationDuration = 180;
|
||||
|
||||
private Building_EquipmentOotheca EquipmentOotheca => (Building_EquipmentOotheca)job.targetA.Thing;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||
this.FailOn(() => EquipmentOotheca == null);
|
||||
|
||||
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell)
|
||||
.FailOnSomeonePhysicallyInteracting(TargetIndex.A);
|
||||
|
||||
yield return Toils_General.WaitWith(TargetIndex.A, 10, true, true);
|
||||
|
||||
var operate = new Toil();
|
||||
operate.initAction = () =>
|
||||
{
|
||||
EquipmentOotheca?.NotifyLarvaArrived(pawn);
|
||||
};
|
||||
operate.tickAction = () =>
|
||||
{
|
||||
pawn.rotationTracker.FaceCell(EquipmentOotheca.Position);
|
||||
};
|
||||
operate.defaultCompleteMode = ToilCompleteMode.Delay;
|
||||
operate.defaultDuration = OperationDuration;
|
||||
operate.WithProgressBar(TargetIndex.A, () =>
|
||||
(float)(OperationDuration - operate.actor.jobs.curDriver.ticksLeftThisToil) / OperationDuration);
|
||||
yield return operate;
|
||||
|
||||
yield return new Toil
|
||||
{
|
||||
initAction = () =>
|
||||
{
|
||||
if (EquipmentOotheca != null && pawn != null && pawn.def.defName == "ArachnaeBase_Race_Larva")
|
||||
{
|
||||
EquipmentOotheca.NotifyLarvaOperationComplete(pawn);
|
||||
pawn.Destroy(DestroyMode.Vanish);
|
||||
}
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Instant
|
||||
};
|
||||
}
|
||||
|
||||
public override string GetReport()
|
||||
{
|
||||
if (EquipmentOotheca != null)
|
||||
{
|
||||
return "ARA_EquipmentIncubator.ActivatingOotheca".Translate();
|
||||
}
|
||||
return base.GetReport();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using RimWorld;
|
||||
// File: Building_Ootheca.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
@@ -32,6 +33,22 @@ namespace ArachnaeSwarm
|
||||
private float qualityProgress = 0f;
|
||||
private float qualityTotal = 0f;
|
||||
|
||||
// 缓存的ModExtension
|
||||
private OothecaIncubatorExtension cachedExtension;
|
||||
|
||||
// 获取ModExtension的辅助属性
|
||||
private OothecaIncubatorExtension Ext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedExtension == null)
|
||||
{
|
||||
cachedExtension = def.GetModExtension<OothecaIncubatorExtension>() ?? OothecaIncubatorExtension.Default;
|
||||
}
|
||||
return cachedExtension;
|
||||
}
|
||||
}
|
||||
|
||||
// 属性访问器
|
||||
public float SpeedMultiplier
|
||||
{
|
||||
@@ -65,92 +82,122 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("IncubationSpeedFactors".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.SpeedFactors".Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
// 1. 检查是否在孵化间中
|
||||
bool inIncubatorRoom = IsInIncubatorRoom();
|
||||
builder.AppendLine(inIncubatorRoom ?
|
||||
"InIncubatorRoom".Translate() :
|
||||
"NotInIncubatorRoom".Translate());
|
||||
if (Ext.requiresIncubatorRoom)
|
||||
{
|
||||
builder.AppendLine(inIncubatorRoom ?
|
||||
"ARA_OothecaIncubator.InIncubatorRoom".Translate() :
|
||||
"ARA_OothecaIncubator.NotInIncubatorRoom".Translate());
|
||||
}
|
||||
|
||||
// 2. 检查营养液数量
|
||||
int nutrientSolutionCount = CountNearbyNutrientSolutions();
|
||||
if (nutrientSolutionCount > 0)
|
||||
{
|
||||
builder.AppendLine("NutrientSolutions".Translate(nutrientSolutionCount, nutrientSolutionCount));
|
||||
builder.AppendLine("ARA_OothecaIncubator.NutrientSolutions".Translate(
|
||||
nutrientSolutionCount,
|
||||
nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile * 100));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine("NoNutrientSolutionsNearby".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.NoNutrientSolutionsNearby".Translate());
|
||||
}
|
||||
|
||||
// 显示检测半径
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_OothecaIncubator.NutrientDetectionRadius".Translate(Ext.nutrientSolutionRadius));
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("TotalSpeedMultiplier".Translate(SpeedMultiplier.ToStringPercent()));
|
||||
builder.AppendLine("ARA_OothecaIncubator.TotalSpeedMultiplier".Translate(SpeedMultiplier.ToStringPercent()));
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 获取质量乘数的详细因子信息(用于工具提示)
|
||||
public string GetQualityFactorsDescription()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("IncubationQualityFactors".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.QualityFactors".Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
// 1. 建筑血量损失百分比
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
builder.AppendLine("BuildingHealth".Translate(healthPercent.ToStringPercent()));
|
||||
// 1. 建筑血量损失百分比(如果启用)
|
||||
if (Ext.healthAffectsQuality)
|
||||
{
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
builder.AppendLine("ARA_OothecaIncubator.BuildingHealth".Translate(healthPercent.ToStringPercent()));
|
||||
}
|
||||
|
||||
// 2. 房间的ARA_IncubatorQualityFactor
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
builder.AppendLine(roomFactor == 1.0f ?
|
||||
"RoomFactorNormal".Translate() :
|
||||
$"{(roomFactor > 1.0f ? "✓" : "✗")} {"RoomFactorModified".Translate()}{roomFactor.ToStringPercent()}");
|
||||
// 2. 房间的ARA_IncubatorQualityFactor(如果启用)
|
||||
if (Ext.useRoomQualityFactor)
|
||||
{
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
builder.AppendLine(roomFactor == 1.0f ?
|
||||
"ARA_OothecaIncubator.RoomFactorNormal".Translate() :
|
||||
$"{(roomFactor > 1.0f ? "✓" : "✗")} {"ARA_OothecaIncubator.RoomFactorModified".Translate()}{roomFactor.ToStringPercent()}");
|
||||
}
|
||||
|
||||
// 3. 附近每一个ARA_Pawn_Ootheca,每一个-10%
|
||||
// 3. 附近每一个ARA_Pawn_Ootheca的惩罚
|
||||
int nearbyOothecaCount = CountNearbyOtherOothecas();
|
||||
if (nearbyOothecaCount > 0)
|
||||
{
|
||||
builder.AppendLine("NearbyOothecas".Translate(nearbyOothecaCount, Mathf.Min(nearbyOothecaCount * 10, 100)));
|
||||
builder.AppendLine("ARA_OothecaIncubator.NearbyOothecas".Translate(
|
||||
nearbyOothecaCount,
|
||||
Mathf.Min(nearbyOothecaCount * Ext.nearbyOothecaPenaltyPerUnit * 100, 100)));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine("NoNearbyOothecas".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.NoNearbyOothecas".Translate());
|
||||
}
|
||||
|
||||
// 显示检测半径
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("ARA_OothecaIncubator.OothecaDetectionRadius".Translate(Ext.nearbyOothecaRadius));
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("TotalQualityMultiplier".Translate(QualityMultiplier.ToStringPercent()));
|
||||
builder.AppendLine("ARA_OothecaIncubator.TotalQualityMultiplier".Translate(QualityMultiplier.ToStringPercent()));
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 构建呼叫幼虫描述
|
||||
private string BuildCallLarvaDescription(IncubationConfig config)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("CallALarvaToActivate".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.CallLarvaTitle".Translate());
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("LarvaWillComeToTheOotheca".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.LarvaWillCome".Translate());
|
||||
builder.AppendLine(config.pawnKind.LabelCap);
|
||||
builder.AppendLine();
|
||||
|
||||
// 显示幼虫搜索半径
|
||||
if (Ext.larvaSearchRadius < 999f)
|
||||
{
|
||||
builder.AppendLine("ARA_OothecaIncubator.LarvaSearchRadius".Translate(Ext.larvaSearchRadius));
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
// 呼叫幼虫
|
||||
private void CallLarva()
|
||||
{
|
||||
// 检查是否已经在孵化中或有幼虫在任务中
|
||||
if (isIncubating)
|
||||
{
|
||||
Messages.Message("AlreadyIncubating".Translate() + " " + "CancelCurrentIncubationFirst".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.AlreadyIncubating".Translate() + " " + "ARA_OothecaIncubator.CancelFirst".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
|
||||
if (assignedLarva != null)
|
||||
{
|
||||
Messages.Message("LarvaAlreadyOnTheWay".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.LarvaAlreadyOnWay".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
@@ -159,7 +206,7 @@ namespace ArachnaeSwarm
|
||||
var larva = FindLarva();
|
||||
if (larva == null)
|
||||
{
|
||||
Messages.Message("NoAvailableLarvaeFound".Translate() + " " + "LarvaMustBeOfRace".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.NoLarvaeFound".Translate() + " " + "ARA_OothecaIncubator.LarvaMustBeRace".Translate(),
|
||||
MessageTypeDefOf.RejectInput);
|
||||
return;
|
||||
}
|
||||
@@ -171,9 +218,10 @@ namespace ArachnaeSwarm
|
||||
|
||||
assignedLarva = larva;
|
||||
|
||||
Messages.Message("LarvaCalled".Translate() + " " + "ItWillArriveShortly".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.LarvaCalled".Translate() + " " + "ARA_OothecaIncubator.ArriveShortly".Translate(),
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
}
|
||||
|
||||
// 幼虫开始操作
|
||||
public void NotifyLarvaArrived(Pawn larva)
|
||||
{
|
||||
@@ -189,9 +237,10 @@ namespace ArachnaeSwarm
|
||||
assignedLarva = larva;
|
||||
|
||||
// 显示消息
|
||||
Messages.Message("LarvaHasArrived".Translate() + " " + "AndIsActivatingTheOotheca".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.LarvaArrived".Translate() + " " + "ARA_OothecaIncubator.ActivatingOotheca".Translate(),
|
||||
MessageTypeDefOf.SilentInput);
|
||||
}
|
||||
|
||||
// 幼虫完成操作(由JobDriver调用)
|
||||
public void NotifyLarvaOperationComplete(Pawn larva)
|
||||
{
|
||||
@@ -228,10 +277,11 @@ namespace ArachnaeSwarm
|
||||
larvaOperateTicksRemaining = 0;
|
||||
|
||||
// 显示消息
|
||||
Messages.Message("IncubationStartedFor".Translate() + " " + incubatingPawnKind.LabelCap + ". " +
|
||||
"ProcessWillCompleteIn".Translate() + " " + config.daysRequired + " " + "DaysBaseTime".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.IncubationStarted".Translate() + " " + incubatingPawnKind.LabelCap + ". " +
|
||||
"ARA_OothecaIncubator.ProcessWillComplete".Translate() + " " + config.daysRequired + " " + "ARA_OothecaIncubator.DaysBaseTime".Translate(),
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
}
|
||||
|
||||
// 取消孵化
|
||||
private void CancelIncubation()
|
||||
{
|
||||
@@ -244,9 +294,10 @@ namespace ArachnaeSwarm
|
||||
qualityProgress = 0f;
|
||||
qualityTotal = 0f;
|
||||
|
||||
Messages.Message("IncubationCancelled".Translate() + " " + "ContentsLost".Translate(),
|
||||
Messages.Message("ARA_OothecaIncubator.IncubationCancelled".Translate() + " " + "ARA_OothecaIncubator.ContentsLost".Translate(),
|
||||
MessageTypeDefOf.NeutralEvent);
|
||||
}
|
||||
|
||||
// 完成孵化
|
||||
private void CompleteIncubation()
|
||||
{
|
||||
@@ -277,16 +328,19 @@ namespace ArachnaeSwarm
|
||||
qualityTotal = 0f;
|
||||
|
||||
// 显示消息
|
||||
string qualityText = finalQualityPercent >= 0.9f ? "QualityExcellent".Translate() :
|
||||
finalQualityPercent >= 0.7f ? "QualityGood".Translate() :
|
||||
finalQualityPercent >= 0.5f ? "QualityAverage".Translate() :
|
||||
finalQualityPercent >= 0.3f ? "QualityPoor".Translate() : "QualityVeryPoor".Translate();
|
||||
string qualityText = finalQualityPercent >= 0.9f ? "ARA_OothecaIncubator.QualityExcellent".Translate() :
|
||||
finalQualityPercent >= 0.7f ? "ARA_OothecaIncubator.QualityGood".Translate() :
|
||||
finalQualityPercent >= 0.5f ? "ARA_OothecaIncubator.QualityAverage".Translate() :
|
||||
finalQualityPercent >= 0.3f ? "ARA_OothecaIncubator.QualityPoor".Translate() : "ARA_OothecaIncubator.QualityVeryPoor".Translate();
|
||||
|
||||
Messages.Message("IncubationComplete".Translate() + " " + pawn.LabelCap + " " +
|
||||
"HasEmergedWith".Translate() + " " + qualityText + " " +
|
||||
"quality".Translate() + " (" + finalQualityPercent.ToStringPercent() + ").",
|
||||
Messages.Message("ARA_OothecaIncubator.IncubationComplete".Translate() + " " + pawn.LabelCap + " " +
|
||||
"ARA_OothecaIncubator.HasEmergedWith".Translate() + " " + qualityText + " " +
|
||||
"ARA_OothecaIncubator.Quality".Translate() + " (" + finalQualityPercent.ToStringPercent() + ").",
|
||||
MessageTypeDefOf.PositiveEvent);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// 显示额外信息(简化版本,只显示速率,不显示因子)
|
||||
public override string GetInspectString()
|
||||
{
|
||||
@@ -305,23 +359,23 @@ namespace ArachnaeSwarm
|
||||
float hoursRemaining = GetRemainingHours();
|
||||
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("Incubating".Translate() + ": " + incubatingPawnKind.LabelCap);
|
||||
builder.Append("ARA_OothecaIncubator.Incubating".Translate() + ": " + incubatingPawnKind.LabelCap);
|
||||
builder.AppendLine();
|
||||
builder.Append("Progress".Translate() + ": " + progressPercent.ToStringPercent());
|
||||
builder.Append("ARA_OothecaIncubator.Progress".Translate() + ": " + progressPercent.ToStringPercent());
|
||||
builder.AppendLine();
|
||||
|
||||
// 显示剩余时间
|
||||
string timeText = "TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "Days".Translate();
|
||||
string timeText = "ARA_OothecaIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
{
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "Hours".Translate() + ")";
|
||||
timeText += " (" + hoursRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.Hours".Translate() + ")";
|
||||
}
|
||||
builder.Append(timeText);
|
||||
|
||||
// 显示速度和质量(简化版本)
|
||||
builder.AppendLine();
|
||||
builder.Append("Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"Quality".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
builder.Append("ARA_OothecaIncubator.Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_OothecaIncubator.Quality".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
else if (assignedLarva != null)
|
||||
{
|
||||
@@ -329,11 +383,11 @@ namespace ArachnaeSwarm
|
||||
if (larvaOperateTicksRemaining > 0)
|
||||
{
|
||||
float secondsRemaining = larvaOperateTicksRemaining / 60f;
|
||||
builder.Append("LarvaIsOperating".Translate() + ": " + secondsRemaining.ToString("F1") + " " + "SRemaining".Translate());
|
||||
builder.Append("ARA_OothecaIncubator.LarvaOperating".Translate() + ": " + secondsRemaining.ToString("F1") + " " + "ARA_OothecaIncubator.SRemaining".Translate());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("LarvaIsOnTheWay".Translate());
|
||||
builder.Append("ARA_OothecaIncubator.LarvaOnWay".Translate());
|
||||
}
|
||||
}
|
||||
else if (!isIncubating)
|
||||
@@ -342,12 +396,12 @@ namespace ArachnaeSwarm
|
||||
if (config != null)
|
||||
{
|
||||
if (builder.Length > 0) builder.AppendLine();
|
||||
builder.Append("Target".Translate() + ": " + config.pawnKind.LabelCap);
|
||||
builder.Append("ARA_OothecaIncubator.Target".Translate() + ": " + config.pawnKind.LabelCap);
|
||||
|
||||
// 只显示当前乘数,不显示条件详情
|
||||
builder.AppendLine();
|
||||
builder.Append("SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"QualityMultiplier".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
builder.Append("ARA_OothecaIncubator.SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
|
||||
"ARA_OothecaIncubator.QualityMultiplier".Translate() + ": " + QualityMultiplier.ToStringPercent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,9 +458,9 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "CallLarva".Translate(),
|
||||
defaultLabel = "ARA_OothecaIncubator.CallLarva".Translate(),
|
||||
defaultDesc = BuildCallLarvaDescription(config),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/CallLarva", false) ?? BaseContent.BadTex,
|
||||
icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_CallLarva", false) ?? BaseContent.BadTex,
|
||||
action = CallLarva,
|
||||
hotKey = KeyBindingDefOf.Misc3
|
||||
};
|
||||
@@ -417,8 +471,8 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "CancelIncubation".Translate(),
|
||||
defaultDesc = "CancelIncubationDesc".Translate(),
|
||||
defaultLabel = "ARA_OothecaIncubator.CancelIncubation".Translate(),
|
||||
defaultDesc = "ARA_OothecaIncubator.CancelIncubationDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Cancel", false) ?? TexCommand.ClearPrioritizedWork,
|
||||
action = CancelIncubation
|
||||
};
|
||||
@@ -461,9 +515,9 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
if (config != null && config.pawnKind != null)
|
||||
{
|
||||
return (props?.buttonLabel ?? "Incubate: {0}").Translate(config.pawnKind.LabelCap);
|
||||
return (props?.buttonLabel ?? "ARA_OothecaIncubator.IncubateLabel").Translate(config.pawnKind.LabelCap);
|
||||
}
|
||||
return (props?.buttonLabel ?? "Incubate: {0}").Translate("None");
|
||||
return (props?.buttonLabel ?? "ARA_OothecaIncubator.IncubateLabel").Translate("None");
|
||||
}
|
||||
|
||||
// 构建切换按钮描述
|
||||
@@ -472,7 +526,7 @@ namespace ArachnaeSwarm
|
||||
var builder = new StringBuilder();
|
||||
|
||||
// 第一部分:按钮功能说明
|
||||
builder.AppendLine((props?.buttonDesc ?? "IncubatorButtonDesc").Translate());
|
||||
builder.AppendLine((props?.buttonDesc ?? "ARA_OothecaIncubator.ButtonDesc").Translate());
|
||||
builder.AppendLine();
|
||||
|
||||
if (config != null)
|
||||
@@ -480,14 +534,14 @@ namespace ArachnaeSwarm
|
||||
// 第二部分:当前选择的详细信息
|
||||
if (config.pawnKind != null)
|
||||
{
|
||||
builder.AppendLine($"IncubatorButtonLabel".Translate(config.pawnKind.LabelCap));
|
||||
builder.AppendLine($"ARA_OothecaIncubator.ButtonLabel".Translate(config.pawnKind.LabelCap));
|
||||
if (!string.IsNullOrEmpty(config.pawnKind.description))
|
||||
{
|
||||
builder.AppendLine(config.pawnKind.description);
|
||||
}
|
||||
}
|
||||
|
||||
builder.AppendLine($"IncubationTime".Translate(config.daysRequired));
|
||||
builder.AppendLine($"ARA_OothecaIncubator.IncubationTime".Translate(config.daysRequired));
|
||||
|
||||
if (config.requiredResearch != null)
|
||||
{
|
||||
@@ -503,7 +557,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("IncubatorButtonDesc".Translate());
|
||||
builder.AppendLine("ARA_OothecaIncubator.ButtonDesc".Translate());
|
||||
|
||||
return builder.ToString().TrimEndNewlines();
|
||||
}
|
||||
@@ -555,7 +609,7 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
option.Label = prefix + label;
|
||||
option.Disabled = true;
|
||||
option.tooltip = description + "\n\n "+ "ResearchRequired".Translate() + " " + config.requiredResearch.LabelCap;
|
||||
option.tooltip = description + "\n\n "+ "ARA_OothecaIncubator.ResearchRequired".Translate() + " " + config.requiredResearch.LabelCap;
|
||||
}
|
||||
|
||||
options.Add(option);
|
||||
@@ -564,7 +618,7 @@ namespace ArachnaeSwarm
|
||||
if (options.Count > 0)
|
||||
{
|
||||
Find.WindowStack.Add(new FloatMenu(options,
|
||||
(props?.menuTitle ?? "Select Incubation Target").Translate()));
|
||||
(props?.menuTitle ?? "ARA_OothecaIncubator.MenuTitle").Translate()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,24 +631,35 @@ namespace ArachnaeSwarm
|
||||
var config = IncubatorData.SelectedConfig;
|
||||
if (config != null && config.pawnKind != null)
|
||||
{
|
||||
Messages.Message($"Incubation target switched to: {config.pawnKind.LabelCap}",
|
||||
Messages.Message($"ARA_OothecaIncubator.TargetSwitched".Translate(config.pawnKind.LabelCap),
|
||||
this, MessageTypeDefOf.SilentInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找幼虫 - 现在通过种族查找
|
||||
// 查找幼虫 - 现在通过种族查找,并考虑搜索半径
|
||||
private Pawn FindLarva()
|
||||
{
|
||||
// 查找地图中属于玩家派系的ArachnaeBase_Race_Larva幼虫
|
||||
var map = Map;
|
||||
if (map == null) return null;
|
||||
|
||||
// 获取搜索半径
|
||||
float searchRadius = Ext.larvaSearchRadius;
|
||||
|
||||
foreach (var pawn in map.mapPawns.SpawnedPawnsInFaction(Faction))
|
||||
{
|
||||
// 检查pawn种族是否为幼虫
|
||||
if (pawn.def.defName == "ArachnaeBase_Race_Larva")
|
||||
{
|
||||
// 检查是否在搜索半径内(如果搜索半径小于999)
|
||||
if (searchRadius < 999f)
|
||||
{
|
||||
float distance = pawn.Position.DistanceTo(Position);
|
||||
if (distance > searchRadius)
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查pawn是否能够移动且没有其他重要任务
|
||||
if (!pawn.Downed && !pawn.InMentalState &&
|
||||
pawn.mindState != null &&
|
||||
@@ -647,62 +712,33 @@ namespace ArachnaeSwarm
|
||||
// 应用质量效果到生成的pawn
|
||||
private void ApplyQualityEffects(Pawn pawn, float qualityPercent)
|
||||
{
|
||||
//// 质量影响:根据质量百分比调整pawn的属性
|
||||
//if (qualityPercent < 1.0f)
|
||||
//{
|
||||
// // 1. 健康影响
|
||||
// float healthFactor = Mathf.Lerp(0.5f, 1.0f, qualityPercent);
|
||||
// if (healthFactor < 1.0f)
|
||||
// {
|
||||
// // 减少最大生命值
|
||||
// foreach (var part in pawn.health.hediffSet.GetNotMissingParts())
|
||||
// {
|
||||
// var healthDiff = part.def.GetMaxHealth(pawn) * (1.0f - healthFactor);
|
||||
// if (healthDiff > 0)
|
||||
// {
|
||||
// pawn.health.AddHediff(HediffDefOf.Bruise, part);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 2. 年龄影响(如果质量低,pawn可能会以较大年龄出生)
|
||||
// if (qualityPercent < 0.6f)
|
||||
// {
|
||||
// float ageBonus = (1.0f - qualityPercent) * 5; // 最多增加5岁
|
||||
// pawn.ageTracker.AgeBiologicalTicks += (long)(ageBonus * 3600000f); // 每岁约3600000ticks
|
||||
// }
|
||||
|
||||
// // 3. 能力影响
|
||||
// if (pawn.skills != null && qualityPercent < 0.8f)
|
||||
// {
|
||||
// float skillFactor = Mathf.Lerp(0.5f, 1.0f, qualityPercent);
|
||||
// foreach (var skill in pawn.skills.skills)
|
||||
// {
|
||||
// skill.levelInt = Mathf.RoundToInt(skill.levelInt * skillFactor);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
// 质量影响:根据质量百分比调整pawn的属性
|
||||
// 这里可以添加具体的质量效果逻辑
|
||||
}
|
||||
|
||||
// 检查是否在孵化间中
|
||||
private bool IsInIncubatorRoom()
|
||||
{
|
||||
// 如果不要求孵化间,总是返回true
|
||||
if (!Ext.requiresIncubatorRoom)
|
||||
return true;
|
||||
|
||||
var room = this.GetRoom();
|
||||
if (room == null) return false;
|
||||
|
||||
return room.Role != null && room.Role.defName == "ARA_Incubator_Room";
|
||||
}
|
||||
|
||||
// 计算周围5格内的营养液数量
|
||||
// 计算周围指定半径内的营养液数量
|
||||
private int CountNearbyNutrientSolutions()
|
||||
{
|
||||
var map = Map;
|
||||
if (map == null) return 0;
|
||||
|
||||
int count = 0;
|
||||
int radius = 5; // 4格半径
|
||||
int radius = Ext.NutrientSolutionRadiusInt;
|
||||
|
||||
// 检查周围5格范围内的所有单元格
|
||||
// 检查指定半径范围内的所有单元格
|
||||
for (int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
@@ -728,6 +764,10 @@ namespace ArachnaeSwarm
|
||||
// 计算房间质量因子
|
||||
private float GetRoomQualityFactor()
|
||||
{
|
||||
// 如果不使用房间质量因子,返回1.0
|
||||
if (!Ext.useRoomQualityFactor)
|
||||
return 1.0f;
|
||||
|
||||
var room = this.GetRoom();
|
||||
if (room == null) return 1.0f;
|
||||
|
||||
@@ -759,17 +799,32 @@ namespace ArachnaeSwarm
|
||||
// 检查是否为ARA_Pawn_Ootheca
|
||||
if (building.def.defName == "ARA_Pawn_Ootheca")
|
||||
{
|
||||
// 检查是否在同一个房间或附近
|
||||
var room = building.GetRoom();
|
||||
if (room != null)
|
||||
bool isNearby = false;
|
||||
|
||||
// 检查是否在同房间内
|
||||
if (Ext.checkSameRoomForOotheca)
|
||||
{
|
||||
// 如果在同一个房间,或者距离较近(5格内)
|
||||
float distance = building.Position.DistanceTo(this.Position);
|
||||
if (room == this.GetRoom() || distance <= 5f)
|
||||
var room = building.GetRoom();
|
||||
if (room != null && room == this.GetRoom())
|
||||
{
|
||||
count++;
|
||||
isNearby = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否在指定半径内
|
||||
if (!isNearby)
|
||||
{
|
||||
float distance = building.Position.DistanceTo(this.Position);
|
||||
if (distance <= Ext.nearbyOothecaRadius)
|
||||
{
|
||||
isNearby = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNearby)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,15 +836,15 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
float multiplier = 1.0f;
|
||||
|
||||
// 1. 检查是否在孵化间中
|
||||
if (!IsInIncubatorRoom())
|
||||
// 1. 检查是否在孵化间中(如果要求)
|
||||
if (Ext.requiresIncubatorRoom && !IsInIncubatorRoom())
|
||||
{
|
||||
multiplier *= 0.8f; // 不在孵化间中,速度80%
|
||||
multiplier *= Ext.speedPenaltyOutsideIncubator; // 应用惩罚
|
||||
}
|
||||
|
||||
// 2. 计算周围营养液的加成
|
||||
int nutrientSolutionCount = CountNearbyNutrientSolutions();
|
||||
float nutrientBonus = 1.0f + (nutrientSolutionCount * 0.01f); // 每个+1%
|
||||
float nutrientBonus = 1.0f + (nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile);
|
||||
|
||||
multiplier *= nutrientBonus;
|
||||
|
||||
@@ -802,17 +857,23 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
float multiplier = 1.0f;
|
||||
|
||||
// 1. 建筑血量损失百分比
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
multiplier *= healthPercent;
|
||||
// 1. 建筑血量损失百分比(如果启用)
|
||||
if (Ext.healthAffectsQuality)
|
||||
{
|
||||
float healthPercent = (float)HitPoints / MaxHitPoints;
|
||||
multiplier *= healthPercent;
|
||||
}
|
||||
|
||||
// 2. 房间的ARA_IncubatorQualityFactor
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
multiplier *= roomFactor;
|
||||
// 2. 房间的ARA_IncubatorQualityFactor(如果启用)
|
||||
if (Ext.useRoomQualityFactor)
|
||||
{
|
||||
float roomFactor = GetRoomQualityFactor();
|
||||
multiplier *= roomFactor;
|
||||
}
|
||||
|
||||
// 3. 附近每一个ARA_Pawn_Ootheca,每一个-10%
|
||||
// 3. 附近每一个ARA_Pawn_Ootheca的惩罚
|
||||
int nearbyOothecaCount = CountNearbyOtherOothecas();
|
||||
float oothecaPenalty = Mathf.Max(0f, 1.0f - (nearbyOothecaCount * 0.10f)); // 最多减到0
|
||||
float oothecaPenalty = Mathf.Max(0f, 1.0f - (nearbyOothecaCount * Ext.nearbyOothecaPenaltyPerUnit));
|
||||
multiplier *= oothecaPenalty;
|
||||
|
||||
// 确保乘数在合理范围内(0-1)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// File: ModExtensions/OothecaIncubatorExtension.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class OothecaIncubatorExtension : DefModExtension
|
||||
{
|
||||
// 营养液检测半径(单位:格)
|
||||
public float nutrientSolutionRadius = 5f;
|
||||
|
||||
// 其他卵距离检测半径(单位:格)
|
||||
public float nearbyOothecaRadius = 5f;
|
||||
|
||||
// 是否检查同房间内的其他卵(默认:是)
|
||||
public bool checkSameRoomForOotheca = true;
|
||||
|
||||
// 营养液加成比例(每个营养液增加多少百分比的速度)
|
||||
public float nutrientSolutionBonusPerTile = 0.01f; // 默认每个+1%
|
||||
|
||||
// 附近其他卵的惩罚比例(每个减少多少百分比的质量)
|
||||
public float nearbyOothecaPenaltyPerUnit = 0.10f; // 默认每个-10%
|
||||
|
||||
// 幼虫搜索半径(单位:格)
|
||||
public float larvaSearchRadius = 999f; // 默认在整个地图搜索
|
||||
|
||||
// 是否需要在孵化间内才能正常工作(默认:否)
|
||||
public bool requiresIncubatorRoom = false;
|
||||
|
||||
// 不在孵化间内的速度惩罚(百分比)
|
||||
public float speedPenaltyOutsideIncubator = 0.8f; // 默认80%
|
||||
|
||||
// 质量因子房间检查(默认:是)
|
||||
public bool useRoomQualityFactor = true;
|
||||
|
||||
// 建筑血量影响质量(默认:是)
|
||||
public bool healthAffectsQuality = true;
|
||||
|
||||
// 获取营养液检测半径的整数形式(用于循环)
|
||||
public int NutrientSolutionRadiusInt => (int)nutrientSolutionRadius;
|
||||
|
||||
// 获取其他卵距离检测半径的整数形式
|
||||
public int NearbyOothecaRadiusInt => (int)nearbyOothecaRadius;
|
||||
|
||||
public static OothecaIncubatorExtension Get(Thing thing)
|
||||
{
|
||||
if (thing?.def?.GetModExtension<OothecaIncubatorExtension>() is OothecaIncubatorExtension ext)
|
||||
return ext;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 验证配置是否有效
|
||||
public bool IsValid()
|
||||
{
|
||||
return nutrientSolutionRadius >= 0f &&
|
||||
nearbyOothecaRadius >= 0f &&
|
||||
nutrientSolutionBonusPerTile >= 0f &&
|
||||
nearbyOothecaPenaltyPerUnit >= 0f;
|
||||
}
|
||||
|
||||
// 获取默认扩展(用于兼容性)
|
||||
public static OothecaIncubatorExtension Default => new OothecaIncubatorExtension();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// File: JobDriver_ExtractHoney.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_ExtractHoney : JobDriver
|
||||
{
|
||||
private const int ExtractDurationTicks = 180; // 3秒 = 180 ticks
|
||||
|
||||
private Need_HoneyProduction HoneyNeed => pawn.needs?.TryGetNeed<Need_HoneyProduction>();
|
||||
|
||||
// 使用挤出效果
|
||||
private static readonly EffecterDef ExtractEffect = ARA_EffecterDefOf.EatVegetarian;
|
||||
private static readonly SoundDef ExtractSound = SoundDefOf.RawMeat_Eat;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
// 只需要保留目标位置
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 确保自身有蜜罐需求且达到挤出阈值
|
||||
this.FailOn(() => HoneyNeed == null || !CanExtract(HoneyNeed));
|
||||
|
||||
// Toil 1: 移动到目标位置
|
||||
yield return Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.Touch);
|
||||
|
||||
// Toil 2: 执行挤出工作
|
||||
Toil extractToil = new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 初始化挤出动作
|
||||
},
|
||||
tickAction = delegate
|
||||
{
|
||||
// 什么都不做,等待完成
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Delay,
|
||||
defaultDuration = ExtractDurationTicks
|
||||
};
|
||||
|
||||
// 添加特效和音效
|
||||
extractToil.WithEffect(() => ExtractEffect, TargetIndex.A);
|
||||
extractToil.PlaySustainerOrSound(() => ExtractSound);
|
||||
|
||||
extractToil.AddFinishAction(delegate
|
||||
{
|
||||
// 执行挤出逻辑
|
||||
ExtractHoney();
|
||||
});
|
||||
|
||||
extractToil.WithProgressBar(TargetIndex.A,
|
||||
() => extractToil.actor.jobs.curDriver.ticksLeftThisToil / (float)ExtractDurationTicks);
|
||||
|
||||
yield return extractToil;
|
||||
|
||||
// Toil 3: 完成后的清理
|
||||
yield return new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 可以在这里检查是否还需要继续挤出
|
||||
// 如果蜜罐存量达到阈值,可以安排下一个挤出工作
|
||||
if (HoneyNeed != null && CanExtract(HoneyNeed))
|
||||
{
|
||||
pawn.jobs.jobQueue.EnqueueLast(CreateExtractJob());
|
||||
}
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Instant
|
||||
};
|
||||
}
|
||||
|
||||
// 检查是否可以挤出(根据MaxLevel决定阈值)
|
||||
private bool CanExtract(Need_HoneyProduction honeyNeed)
|
||||
{
|
||||
// 如果MaxLevel大于1.5,需要超过80%储量才考虑挤蜜
|
||||
if (honeyNeed.MaxLevel > 1.5f)
|
||||
{
|
||||
return honeyNeed.CurLevelPercentage > 0.8f;
|
||||
}
|
||||
// 否则在大于1时挤蜜
|
||||
else
|
||||
{
|
||||
return honeyNeed.CurLevel >= 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取挤出阈值(用于显示等)
|
||||
private float GetExtractThreshold(Need_HoneyProduction honeyNeed)
|
||||
{
|
||||
if (honeyNeed.MaxLevel > 1.5f)
|
||||
{
|
||||
return honeyNeed.MaxLevel * 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 挤出蜂蜜的逻辑
|
||||
private void ExtractHoney()
|
||||
{
|
||||
if (HoneyNeed == null)
|
||||
return;
|
||||
|
||||
// 计算要生成的虫蜜数量(蜜罐等级整数部分)
|
||||
int jellyCount = (int)HoneyNeed.CurLevel;
|
||||
|
||||
// 确保至少生成1个
|
||||
if (jellyCount < 1)
|
||||
return;
|
||||
|
||||
// 创建虫蜜
|
||||
Thing jelly = ThingMaker.MakeThing(DefDatabase<ThingDef>.GetNamed("ARA_InsectJelly"));
|
||||
jelly.stackCount = jellyCount;
|
||||
|
||||
// 尝试将虫蜜放在目标位置
|
||||
GenPlace.TryPlaceThing(jelly, job.targetA.Cell, pawn.Map, ThingPlaceMode.Near);
|
||||
|
||||
// 减少蜜罐存量
|
||||
HoneyNeed.ExtractHoney(jellyCount);
|
||||
|
||||
// 播放视觉反馈
|
||||
MoteMaker.ThrowText(job.targetA.Cell.ToVector3Shifted(), pawn.Map,"ARA_ExtractHoney_Message".Translate(jellyCount));
|
||||
}
|
||||
|
||||
// 创建挤出工作的辅助方法
|
||||
private Job CreateExtractJob()
|
||||
{
|
||||
// 寻找最近的空地
|
||||
IntVec3 targetCell = FindNearestEmptyCell(pawn.Position, pawn.Map);
|
||||
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_ExtractHoney"), targetCell);
|
||||
return job;
|
||||
}
|
||||
|
||||
// 寻找最近的空单元格
|
||||
private IntVec3 FindNearestEmptyCell(IntVec3 from, Map map)
|
||||
{
|
||||
if (CellFinder.TryFindBestPawnStandCell(pawn, out IntVec3 cell, false))
|
||||
{
|
||||
return cell;
|
||||
}
|
||||
|
||||
// 如果找不到最佳位置,使用原位置
|
||||
return from;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// File: JobDriver_FeedWithHoney.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_FeedWithHoney : JobDriver
|
||||
{
|
||||
private const int FeedDurationTicks = 180; // 3秒 = 180 ticks (60 ticks/秒)
|
||||
private const float FoodTransferPerTick = 0.01f; // 每tick传输的食物量
|
||||
|
||||
private Pawn TargetPawn => job.targetA.Pawn;
|
||||
private Need_HoneyProduction HoneyNeed => pawn.needs?.TryGetNeed<Need_HoneyProduction>();
|
||||
private Need_Food TargetFoodNeed => TargetPawn.needs?.TryGetNeed<Need_Food>();
|
||||
|
||||
// 使用喂养效果 - 参考Toils_Ingest中的用法
|
||||
private static readonly EffecterDef FeedEffect = ARA_EffecterDefOf.EatVegetarian;
|
||||
private static readonly SoundDef FeedSound = SoundDefOf.RawMeat_Eat;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
if (TargetPawn == null || TargetFoodNeed == null || HoneyNeed == null)
|
||||
return false;
|
||||
|
||||
// 保留目标pawn的位置,以便接近
|
||||
return pawn.Reserve(TargetPawn, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 确保目标有效
|
||||
this.FailOnDespawnedOrNull(TargetIndex.A);
|
||||
this.FailOn(() => TargetPawn.Dead || TargetFoodNeed == null || HoneyNeed == null);
|
||||
|
||||
// Toil 1: 移动到目标面前
|
||||
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch)
|
||||
.FailOnDespawnedOrNull(TargetIndex.A);
|
||||
|
||||
// Toil 2: 进行喂养工作(参考Toils_Ingest中的效果添加方式)
|
||||
Toil feedToil = new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 初始化喂养动作
|
||||
},
|
||||
tickAction = delegate
|
||||
{
|
||||
// 每tick检查是否还能继续喂养
|
||||
if (HoneyNeed.CurLevel <= 0 || TargetFoodNeed.CurLevelPercentage >= 1.0f)
|
||||
{
|
||||
ReadyForNextToil();
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算本次tick传输的量
|
||||
float transferAmount = FoodTransferPerTick;
|
||||
float honeyAvailable = HoneyNeed.CurLevel;
|
||||
|
||||
// 确保不超过蜜罐存量
|
||||
if (transferAmount > honeyAvailable)
|
||||
transferAmount = honeyAvailable;
|
||||
|
||||
// 确保不超过目标的需求
|
||||
float targetFoodSpace = TargetFoodNeed.MaxLevel - TargetFoodNeed.CurLevel;
|
||||
if (transferAmount > targetFoodSpace)
|
||||
transferAmount = targetFoodSpace;
|
||||
|
||||
// 执行传输
|
||||
HoneyNeed.ExtractHoney(transferAmount);
|
||||
TargetFoodNeed.CurLevel += transferAmount;
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Delay,
|
||||
defaultDuration = FeedDurationTicks
|
||||
};
|
||||
|
||||
// 添加特效和音效(参考Toils_Ingest.AddIngestionEffects)
|
||||
feedToil.WithEffect(() => FeedEffect, TargetIndex.A);
|
||||
feedToil.PlaySustainerOrSound(() => FeedSound);
|
||||
|
||||
feedToil.AddFinishAction(delegate
|
||||
{
|
||||
// 喂养完成后给予社交互动奖励
|
||||
TargetPawn.interactions?.TryInteractWith(pawn, InteractionDefOf.Chitchat);
|
||||
});
|
||||
|
||||
feedToil.WithProgressBar(TargetIndex.A,
|
||||
() => feedToil.actor.jobs.curDriver.ticksLeftThisToil / (float)FeedDurationTicks,
|
||||
interpolateBetweenActorAndTarget: true);
|
||||
|
||||
yield return feedToil;
|
||||
|
||||
// 修改:移除了第三个Toil中的提示消息,只剩下一个简单的完成Toil
|
||||
yield return new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 这里可以放置任何清理代码,但不要显示消息
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Instant
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// File: ThinkNode_JobGiver_ExtractHoney.cs
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class ThinkNode_JobGiver_ExtractHoney : ThinkNode_JobGiver
|
||||
{
|
||||
private const int ScanIntervalTicks = 300; // 5秒扫描一次
|
||||
|
||||
private int lastScanTick = -99999;
|
||||
|
||||
protected override Job TryGiveJob(Pawn pawn)
|
||||
{
|
||||
// 检查是否应该扫描
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
if (currentTick - lastScanTick < ScanIntervalTicks)
|
||||
return null;
|
||||
|
||||
lastScanTick = currentTick;
|
||||
|
||||
// 检查甲壳剥离组件和开关状态
|
||||
Comp_ChitinStripping stripComp = pawn.TryGetComp<Comp_ChitinStripping>();
|
||||
|
||||
// 检查开关是否开启
|
||||
if (stripComp == null || !stripComp.CanStripChitin || !stripComp.CanStripNow(pawn))
|
||||
return null;
|
||||
|
||||
// 检查自身需求
|
||||
Need_HoneyProduction honeyNeed = pawn.needs?.TryGetNeed<Need_HoneyProduction>();
|
||||
if (honeyNeed == null || !CanExtract(honeyNeed))
|
||||
return null;
|
||||
|
||||
// 如果已经有挤出工作,则不分配新工作
|
||||
if (pawn.CurJob != null && pawn.CurJob.def == DefDatabase<JobDef>.GetNamed("ARA_ExtractHoney"))
|
||||
return null;
|
||||
|
||||
// 寻找最近的空地
|
||||
IntVec3 targetCell = FindNearestEmptyCell(pawn);
|
||||
if (!targetCell.IsValid)
|
||||
return null;
|
||||
|
||||
// 确保可以到达
|
||||
if (!pawn.CanReach(targetCell, PathEndMode.Touch, Danger.Some))
|
||||
return null;
|
||||
|
||||
// 创建挤出工作
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_ExtractHoney"), targetCell);
|
||||
job.count = 1;
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
// 检查是否可以挤出(与JobDriver中的逻辑保持一致)
|
||||
private bool CanExtract(Need_HoneyProduction honeyNeed)
|
||||
{
|
||||
// 如果MaxLevel大于1.5,需要超过80%储量才考虑挤蜜
|
||||
if (honeyNeed.MaxLevel > 1.5f)
|
||||
{
|
||||
return honeyNeed.CurLevelPercentage > 0.8f;
|
||||
}
|
||||
// 否则在大于1时挤蜜
|
||||
else
|
||||
{
|
||||
return honeyNeed.CurLevel >= 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 寻找最近的空单元格
|
||||
private IntVec3 FindNearestEmptyCell(Pawn pawn)
|
||||
{
|
||||
// 首先检查当前位置周围3格内是否有空地
|
||||
for (int radius = 1; radius <= 3; radius++)
|
||||
{
|
||||
foreach (IntVec3 cell in GenRadial.RadialCellsAround(pawn.Position, radius, true))
|
||||
{
|
||||
if (cell.InBounds(pawn.Map) &&
|
||||
cell.Standable(pawn.Map) &&
|
||||
cell.GetFirstItem(pawn.Map) == null &&
|
||||
!cell.GetTerrain(pawn.Map).IsWater)
|
||||
{
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到,使用CellFinder寻找
|
||||
if (CellFinder.TryFindBestPawnStandCell(pawn, out IntVec3 bestCell, false))
|
||||
{
|
||||
return bestCell;
|
||||
}
|
||||
|
||||
// 最后尝试使用原位置(确保不是水面)
|
||||
if (!pawn.Position.GetTerrain(pawn.Map).IsWater)
|
||||
{
|
||||
return pawn.Position;
|
||||
}
|
||||
|
||||
return IntVec3.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// File: ThinkNode_JobGiver_FeedWithHoney.cs
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class ThinkNode_JobGiver_FeedWithHoney : ThinkNode_JobGiver
|
||||
{
|
||||
private const float MinFoodNeedThreshold = 0.2f; // 目标需要喂养的阈值
|
||||
private const float MinHoneyThreshold = 0.1f; // 蜜罐低于10%时不喂养
|
||||
private const int ScanIntervalTicks = 250; // 扫描间隔 (约4秒)
|
||||
private const float MaxDistance = 30f; // 最大寻找距离
|
||||
|
||||
private int lastScanTick = -99999;
|
||||
|
||||
protected override Job TryGiveJob(Pawn pawn)
|
||||
{
|
||||
// 检查是否应该扫描
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
if (currentTick - lastScanTick < ScanIntervalTicks)
|
||||
return null;
|
||||
|
||||
lastScanTick = currentTick;
|
||||
|
||||
// 检查自身需求
|
||||
Need_HoneyProduction honeyNeed = pawn.needs?.TryGetNeed<Need_HoneyProduction>();
|
||||
// 修改:检查蜜罐存量是否低于10%,如果是则不喂养
|
||||
if (honeyNeed == null || honeyNeed.IsEmpty || honeyNeed.CurLevelPercentage < MinHoneyThreshold)
|
||||
return null;
|
||||
|
||||
// 扫描潜在的喂养目标
|
||||
List<Pawn> potentialTargets = new List<Pawn>();
|
||||
|
||||
// 获取地图上所有pawn
|
||||
foreach (Pawn target in pawn.Map.mapPawns.AllPawnsSpawned)
|
||||
{
|
||||
// 跳过自己
|
||||
if (target == pawn)
|
||||
continue;
|
||||
|
||||
// 检查是否属于己方势力(殖民者、奴隶、囚犯)
|
||||
if (!IsFriendlyPawn(pawn, target))
|
||||
continue;
|
||||
|
||||
// 检查距离
|
||||
if (pawn.Position.DistanceTo(target.Position) > MaxDistance)
|
||||
continue;
|
||||
|
||||
// 检查是否需要食物
|
||||
Need_Food targetFoodNeed = target.needs?.TryGetNeed<Need_Food>();
|
||||
if (targetFoodNeed == null || targetFoodNeed.CurLevelPercentage > MinFoodNeedThreshold)
|
||||
continue;
|
||||
|
||||
// 检查目标是否可到达
|
||||
if (!pawn.CanReserveAndReach(target, PathEndMode.Touch, Danger.Some))
|
||||
continue;
|
||||
|
||||
potentialTargets.Add(target);
|
||||
}
|
||||
|
||||
// 如果没有目标
|
||||
if (potentialTargets.Count == 0)
|
||||
return null;
|
||||
|
||||
// 按需求紧急程度排序(最饿的优先)
|
||||
potentialTargets.Sort((a, b) =>
|
||||
{
|
||||
Need_Food foodA = a.needs?.TryGetNeed<Need_Food>();
|
||||
Need_Food foodB = b.needs?.TryGetNeed<Need_Food>();
|
||||
return foodA?.CurLevelPercentage.CompareTo(foodB?.CurLevelPercentage) ?? 0;
|
||||
});
|
||||
|
||||
// 选择最饥饿的目标
|
||||
Pawn targetPawn = potentialTargets[0];
|
||||
|
||||
// 创建喂养工作
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_FeedWithHoney"), targetPawn);
|
||||
job.count = 1;
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
private bool IsFriendlyPawn(Pawn feeder, Pawn target)
|
||||
{
|
||||
// 检查目标是否是殖民者、奴隶或囚犯
|
||||
if (target.Faction == Faction.OfPlayer)
|
||||
return true;
|
||||
|
||||
// 检查是否是囚犯(属于玩家)
|
||||
if (target.IsPrisonerOfColony)
|
||||
return true;
|
||||
|
||||
// 检查是否是奴隶
|
||||
if (target.IsSlaveOfColony)
|
||||
return true;
|
||||
|
||||
// 检查是否和喂养者同一派系
|
||||
if (target.Faction != null && target.Faction == feeder.Faction)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// File: Comps/CompProperties_ChitinStripping.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_ChitinStripping : CompProperties
|
||||
{
|
||||
// 是否允许剥离甲壳
|
||||
public bool canStripChitin = true;
|
||||
|
||||
// 剥离的阈值(甲壳存量的百分比)
|
||||
public float stripThreshold = 0.8f;
|
||||
|
||||
// 每次剥离产生的最小甲壳数量
|
||||
public int minStripAmount = 1;
|
||||
|
||||
// 剥离工作的间隔(ticks)
|
||||
public int stripInterval = 3000; // 50秒
|
||||
|
||||
// 甲壳物品定义
|
||||
public ThingDef carapaceThingDef = null;
|
||||
|
||||
public CompProperties_ChitinStripping()
|
||||
{
|
||||
compClass = typeof(Comp_ChitinStripping);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// File: Comps/Comp_ChitinStripping.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class Comp_ChitinStripping : ThingComp
|
||||
{
|
||||
public CompProperties_ChitinStripping Props => (CompProperties_ChitinStripping)props;
|
||||
|
||||
// 剥离开关状态
|
||||
private bool stripEnabled = true;
|
||||
|
||||
// 上次剥离时间
|
||||
private int lastStripTick = -99999;
|
||||
|
||||
// 属性访问器
|
||||
public bool StripEnabled
|
||||
{
|
||||
get => stripEnabled;
|
||||
set => stripEnabled = value;
|
||||
}
|
||||
|
||||
public bool CanStripChitin => Props.canStripChitin && stripEnabled;
|
||||
|
||||
public float StripThreshold => Props.stripThreshold;
|
||||
|
||||
// 获取甲壳物品定义
|
||||
public ThingDef CarapaceThingDef
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Props.carapaceThingDef != null)
|
||||
return Props.carapaceThingDef;
|
||||
|
||||
return DefDatabase<ThingDef>.GetNamed("ARA_Carapace", false);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否可以剥离
|
||||
public bool CanStripNow(Pawn pawn)
|
||||
{
|
||||
if (!CanStripChitin || pawn == null || pawn.Dead)
|
||||
return false;
|
||||
|
||||
// 检查间隔
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
if (currentTick - lastStripTick < Props.stripInterval)
|
||||
return false;
|
||||
|
||||
// 检查甲壳需求
|
||||
Need_ChitinArmor chitinNeed = pawn.needs?.TryGetNeed<Need_ChitinArmor>();
|
||||
if (chitinNeed == null)
|
||||
return false;
|
||||
|
||||
// 检查是否达到阈值
|
||||
return chitinNeed.CurLevelPercentage >= StripThreshold;
|
||||
}
|
||||
|
||||
// 记录剥离时间
|
||||
public void NotifyStripped()
|
||||
{
|
||||
lastStripTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
|
||||
// 获取上次剥离到现在的时间
|
||||
public int TicksSinceLastStrip => Find.TickManager.TicksGame - lastStripTick;
|
||||
|
||||
// 获取剩余冷却时间
|
||||
public int CooldownTicksRemaining => Mathf.Max(0, Props.stripInterval - TicksSinceLastStrip);
|
||||
|
||||
// 序列化
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref stripEnabled, "stripEnabled", true);
|
||||
Scribe_Values.Look(ref lastStripTick, "lastStripTick", -99999);
|
||||
}
|
||||
|
||||
// 获取Gizmos(命令按钮)
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
// 只在玩家控制的pawn上显示
|
||||
if (parent is Pawn pawn && pawn.Faction?.IsPlayer == true)
|
||||
{
|
||||
// 甲壳剥离开关按钮
|
||||
yield return new Command_Toggle
|
||||
{
|
||||
defaultLabel = "ARA_ChitinStripping_Toggle".Translate(),
|
||||
defaultDesc = "ARA_ChitinStripping_ToggleDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_StripChitin"),
|
||||
isActive = () => stripEnabled,
|
||||
toggleAction = () =>
|
||||
{
|
||||
stripEnabled = !stripEnabled;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// File: JobDriver_StripChitin.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_StripChitin : JobDriver
|
||||
{
|
||||
private const int StripDurationTicks = 300; // 5秒 = 300 ticks
|
||||
|
||||
// 获取甲壳需求
|
||||
private Need_ChitinArmor ChitinNeed => pawn.needs?.TryGetNeed<Need_ChitinArmor>();
|
||||
|
||||
// 获取甲壳剥离组件
|
||||
private Comp_ChitinStripping StripComp
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pawn == null)
|
||||
return null;
|
||||
|
||||
// 从pawn的def中获取Comp
|
||||
CompProperties_ChitinStripping compProps = pawn.def.GetCompProperties<CompProperties_ChitinStripping>();
|
||||
if (compProps != null)
|
||||
{
|
||||
return pawn.TryGetComp<Comp_ChitinStripping>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 特效和音效
|
||||
private static readonly EffecterDef StripEffect = ARA_EffecterDefOf.EatVegetarian;
|
||||
private static readonly SoundDef StripSound = SoundDefOf.RawMeat_Eat;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
// 只需要保留目标位置
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 检查条件
|
||||
this.FailOn(() => ChitinNeed == null);
|
||||
this.FailOn(() => StripComp == null);
|
||||
this.FailOn(() => !StripComp.CanStripNow(pawn));
|
||||
this.FailOn(() => !StripComp.CanStripChitin); // 检查开关
|
||||
|
||||
// Toil 1: 移动到目标位置
|
||||
yield return Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.Touch);
|
||||
|
||||
// Toil 2: 执行剥离工作
|
||||
Toil stripToil = new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 初始化剥离动作
|
||||
},
|
||||
tickAction = delegate
|
||||
{
|
||||
// 什么都不做,等待完成
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Delay,
|
||||
defaultDuration = StripDurationTicks
|
||||
};
|
||||
|
||||
// 添加特效和音效
|
||||
stripToil.WithEffect(() => StripEffect, TargetIndex.A);
|
||||
stripToil.PlaySustainerOrSound(() => StripSound);
|
||||
|
||||
stripToil.AddFinishAction(delegate
|
||||
{
|
||||
// 执行剥离逻辑
|
||||
StripChitin();
|
||||
});
|
||||
|
||||
stripToil.WithProgressBar(TargetIndex.A,
|
||||
() => stripToil.actor.jobs.curDriver.ticksLeftThisToil / (float)StripDurationTicks,
|
||||
interpolateBetweenActorAndTarget: true);
|
||||
|
||||
yield return stripToil;
|
||||
|
||||
// Toil 3: 完成后的清理
|
||||
yield return new Toil
|
||||
{
|
||||
initAction = delegate
|
||||
{
|
||||
// 记录剥离时间
|
||||
StripComp?.NotifyStripped();
|
||||
|
||||
// 如果甲壳存量仍然达到阈值,可以安排下一个剥离工作
|
||||
if (ChitinNeed != null && StripComp != null && StripComp.CanStripNow(pawn))
|
||||
{
|
||||
pawn.jobs.jobQueue.EnqueueLast(CreateStripJob());
|
||||
}
|
||||
},
|
||||
defaultCompleteMode = ToilCompleteMode.Instant
|
||||
};
|
||||
}
|
||||
|
||||
// 剥离甲壳的逻辑
|
||||
private void StripChitin()
|
||||
{
|
||||
if (ChitinNeed == null || StripComp == null)
|
||||
return;
|
||||
|
||||
// 计算要剥离的甲壳数量
|
||||
// 通常剥离整数部分,但至少剥离1个
|
||||
int stripCount = (int)ChitinNeed.CurLevel;
|
||||
if (stripCount < StripComp.Props.minStripAmount)
|
||||
stripCount = StripComp.Props.minStripAmount;
|
||||
|
||||
// 获取甲壳物品定义
|
||||
ThingDef carapaceDef = StripComp.CarapaceThingDef;
|
||||
if (carapaceDef == null)
|
||||
return;
|
||||
|
||||
// 创建甲壳物品
|
||||
Thing carapace = ThingMaker.MakeThing(carapaceDef);
|
||||
carapace.stackCount = stripCount;
|
||||
|
||||
// 尝试将甲壳放在目标位置
|
||||
GenPlace.TryPlaceThing(carapace, job.targetA.Cell, pawn.Map, ThingPlaceMode.Near);
|
||||
|
||||
// 减少甲壳存量
|
||||
ChitinNeed.ReduceChitin(stripCount);
|
||||
|
||||
// 播放视觉反馈
|
||||
MoteMaker.ThrowText(job.targetA.Cell.ToVector3Shifted(), pawn.Map,
|
||||
"ARA_StripChitin_Message".Translate(stripCount));
|
||||
}
|
||||
|
||||
// 创建剥离工作的辅助方法
|
||||
private Job CreateStripJob()
|
||||
{
|
||||
// 寻找最近的空地
|
||||
IntVec3 targetCell = FindNearestEmptyCell(pawn.Position, pawn.Map);
|
||||
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_StripChitin"), targetCell);
|
||||
return job;
|
||||
}
|
||||
|
||||
// 寻找最近的空单元格
|
||||
private IntVec3 FindNearestEmptyCell(IntVec3 from, Map map)
|
||||
{
|
||||
if (CellFinder.TryFindBestPawnStandCell(pawn, out IntVec3 cell, false))
|
||||
{
|
||||
return cell;
|
||||
}
|
||||
|
||||
// 如果找不到最佳位置,使用原位置
|
||||
return from;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// File: ThinkNode_JobGiver_StripChitin.cs
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class ThinkNode_JobGiver_StripChitin : ThinkNode_JobGiver
|
||||
{
|
||||
private const int ScanIntervalTicks = 500; // 8.3秒扫描一次
|
||||
|
||||
private int lastScanTick = -99999;
|
||||
|
||||
protected override Job TryGiveJob(Pawn pawn)
|
||||
{
|
||||
// 检查是否应该扫描
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
if (currentTick - lastScanTick < ScanIntervalTicks)
|
||||
return null;
|
||||
|
||||
lastScanTick = currentTick;
|
||||
|
||||
// 检查甲壳剥离组件
|
||||
Comp_ChitinStripping stripComp = pawn.TryGetComp<Comp_ChitinStripping>();
|
||||
if (stripComp == null || !stripComp.CanStripNow(pawn))
|
||||
return null;
|
||||
|
||||
// 如果已经有剥离工作,则不分配新工作
|
||||
if (pawn.CurJob != null && pawn.CurJob.def == DefDatabase<JobDef>.GetNamed("ARA_StripChitin"))
|
||||
return null;
|
||||
|
||||
// 寻找最近的空地
|
||||
IntVec3 targetCell = FindNearestEmptyCell(pawn);
|
||||
if (!targetCell.IsValid)
|
||||
return null;
|
||||
|
||||
// 确保可以到达
|
||||
if (!pawn.CanReach(targetCell, PathEndMode.Touch, Danger.Some))
|
||||
return null;
|
||||
|
||||
// 创建剥离工作
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_StripChitin"), targetCell);
|
||||
job.count = 1;
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
// 寻找最近的空单元格
|
||||
private IntVec3 FindNearestEmptyCell(Pawn pawn)
|
||||
{
|
||||
// 首先检查当前位置周围3格内是否有空地
|
||||
for (int radius = 1; radius <= 3; radius++)
|
||||
{
|
||||
foreach (IntVec3 cell in GenRadial.RadialCellsAround(pawn.Position, radius, true))
|
||||
{
|
||||
if (cell.InBounds(pawn.Map) &&
|
||||
cell.Standable(pawn.Map) &&
|
||||
cell.GetFirstItem(pawn.Map) == null &&
|
||||
!cell.GetTerrain(pawn.Map).IsWater)
|
||||
{
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到,使用CellFinder寻找
|
||||
if (CellFinder.TryFindBestPawnStandCell(pawn, out IntVec3 bestCell, false))
|
||||
{
|
||||
return bestCell;
|
||||
}
|
||||
|
||||
// 最后尝试使用原位置(确保不是水面)
|
||||
if (!pawn.Position.GetTerrain(pawn.Map).IsWater)
|
||||
{
|
||||
return pawn.Position;
|
||||
}
|
||||
|
||||
return IntVec3.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// File: Jobs/JobDriver_SwarmMaintain.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_SwarmMaintain : JobDriver
|
||||
{
|
||||
// 工作完成后增加的维护度
|
||||
public const float MaintenancePerWork = 25f;
|
||||
|
||||
// 工作时间(ticks)
|
||||
private const int WorkDuration = 600; // 10秒
|
||||
// 使用喂养效果 - 参考Toils_Ingest中的用法
|
||||
private static readonly EffecterDef MaintainEffect = ARA_EffecterDefOf.EatVegetarian;
|
||||
private static readonly SoundDef MaintainSound = SoundDefOf.RawMeat_Eat;
|
||||
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 1. 前往目标建筑
|
||||
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||
yield return Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.Touch);
|
||||
|
||||
// 2. 执行维护工作
|
||||
Toil maintain = new Toil();
|
||||
maintain.tickAction = () =>
|
||||
{
|
||||
Pawn actor = maintain.actor;
|
||||
Thing target = actor.CurJob.targetA.Thing;
|
||||
|
||||
// 检查目标是否仍然有效
|
||||
if (target == null || target.Destroyed)
|
||||
{
|
||||
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 如果有技能要求,可以在这里检查
|
||||
// actor.skills.Learn(SkillDefOf.Construction, 0.05f);
|
||||
};
|
||||
// 添加特效和音效(参考Toils_Ingest.AddIngestionEffects)
|
||||
maintain.WithEffect(() => MaintainEffect, TargetIndex.A);
|
||||
maintain.PlaySustainerOrSound(() => MaintainSound);
|
||||
maintain.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||
maintain.FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);
|
||||
maintain.WithProgressBar(TargetIndex.A, () => (float)maintain.actor.jobs.curDriver.ticksLeftThisToil / WorkDuration);
|
||||
maintain.defaultCompleteMode = ToilCompleteMode.Delay;
|
||||
maintain.defaultDuration = WorkDuration;
|
||||
yield return maintain;
|
||||
|
||||
// 3. 完成工作,增加维护度
|
||||
yield return new Toil
|
||||
{
|
||||
initAction = () =>
|
||||
{
|
||||
Thing target = TargetA.Thing;
|
||||
if (target != null && !target.Destroyed)
|
||||
{
|
||||
Comp_SwarmMaintenance comp = target.TryGetComp<Comp_SwarmMaintenance>();
|
||||
if (comp != null)
|
||||
{
|
||||
comp.AddMaintenance(MaintenancePerWork);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
438
Source/ArachnaeSwarm/Needs/Need_ChitinArmor.cs
Normal file
438
Source/ArachnaeSwarm/Needs/Need_ChitinArmor.cs
Normal file
@@ -0,0 +1,438 @@
|
||||
// File: Need_ChitinArmor.cs
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class NeedDefExtension_ChitinLevels : DefModExtension
|
||||
{
|
||||
// 关联的Hediff
|
||||
public HediffDef hediff = null;
|
||||
|
||||
// 严重性映射范围(默认是1:1映射,即Need值=严重性值)
|
||||
[XmlElement("severityRange")]
|
||||
public FloatRange severityRange = new FloatRange(0f, 1f);
|
||||
|
||||
// 是否死亡时移除Hediff
|
||||
public bool removeOnDeath = true;
|
||||
|
||||
// 基础增长速率系数
|
||||
public float baseGrowthRate = 0.1f;
|
||||
|
||||
// 甲壳数量平方的系数
|
||||
public float squareCoefficient = 1f / 100f; // 默认 1/100
|
||||
}
|
||||
public class Need_ChitinArmor : Need
|
||||
{
|
||||
// 甲壳增长基础值(每tick)
|
||||
private const float BaseChitinGainPerTick = 0.0001f;
|
||||
|
||||
// 关联的Hediff
|
||||
private Hediff chitinHediff;
|
||||
|
||||
// 上次更新Hediff的时间
|
||||
private int lastHediffUpdateTick = -99999;
|
||||
private const int HediffUpdateInterval = 60; // 每60tick更新一次Hediff
|
||||
|
||||
// 甲壳部位名称
|
||||
private const string CHITIN_SHELL_PART_NAME = "ARA_Chitin_Shell";
|
||||
|
||||
// 缓存的身体部位数量(用于减少计算)
|
||||
private int cachedShellPartCount = -1;
|
||||
private int lastPartCountCheckTick = -99999;
|
||||
private const int PartCountCheckInterval = 120; // 每120tick检查一次
|
||||
|
||||
// 获取ModExtension配置
|
||||
public NeedDefExtension_ChitinLevels Extension => def.GetModExtension<NeedDefExtension_ChitinLevels>();
|
||||
|
||||
// 计算甲壳最大值:基础值1 + 每个ARA_Chitin_Shell部位增加1
|
||||
public override float MaxLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
int shellCount = GetChitinShellPartCount();
|
||||
return 1f + shellCount;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前等级百分比(用于UI显示)
|
||||
public new float CurLevelPercentage => CurLevel / MaxLevel;
|
||||
|
||||
// 获取甲壳增长速率
|
||||
public float GrowthRatePerTick
|
||||
{
|
||||
get
|
||||
{
|
||||
int shellCount = GetChitinShellPartCount();
|
||||
|
||||
// 计算增长速率:((甲壳数量的平方) * 系数) + 基础值
|
||||
float squareCoefficient = Extension?.squareCoefficient ?? (1f / 100f);
|
||||
float baseRate = Extension?.baseGrowthRate ?? 0.1f;
|
||||
|
||||
return ((shellCount * shellCount) * squareCoefficient) + baseRate;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取每秒增长速率(用于UI显示)
|
||||
public float GrowthRatePerSecond
|
||||
{
|
||||
get
|
||||
{
|
||||
// RimWorld中,1秒 = 60ticks
|
||||
// 实际每秒增长量 = 每tick增长速率 * 60
|
||||
// 注意:BaseChitinGainPerTick是基础增长值,GrowthRatePerTick是增长系数
|
||||
// 实际增长公式:每tick增长量 = BaseChitinGainPerTick * GrowthRatePerTick
|
||||
// 所以每秒增长量 = BaseChitinGainPerTick * GrowthRatePerTick * 60
|
||||
return BaseChitinGainPerTick * GrowthRatePerTick * 60f;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取每2.5秒增长速率(用于UI显示,每150tick)
|
||||
public float GrowthRatePer2_5Seconds => GrowthRatePerSecond * 2.5f;
|
||||
|
||||
public Need_ChitinArmor(Pawn newPawn) : base(newPawn)
|
||||
{
|
||||
// 初始化时设置为空
|
||||
curLevelInt = 0f;
|
||||
|
||||
// 设置默认阈值点
|
||||
SetDefaultThresholds();
|
||||
|
||||
// 初始化缓存
|
||||
UpdateCachedShellPartCount();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_References.Look(ref chitinHediff, "chitinHediff");
|
||||
Scribe_Values.Look(ref cachedShellPartCount, "cachedShellPartCount", -1);
|
||||
Scribe_Values.Look(ref lastPartCountCheckTick, "lastPartCountCheckTick", -99999);
|
||||
}
|
||||
|
||||
private void SetDefaultThresholds()
|
||||
{
|
||||
// 默认阈值:25%、50%、75%(用于UI显示)
|
||||
threshPercents = new List<float> { 0.25f, 0.5f, 0.75f };
|
||||
}
|
||||
|
||||
public override void NeedInterval()
|
||||
{
|
||||
// 检查是否需要冻结
|
||||
if (IsFrozen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 定期更新身体部位数量缓存
|
||||
int currentTick = Find.TickManager.TicksGame;
|
||||
if (currentTick - lastPartCountCheckTick >= PartCountCheckInterval)
|
||||
{
|
||||
UpdateCachedShellPartCount();
|
||||
lastPartCountCheckTick = currentTick;
|
||||
}
|
||||
|
||||
// 计算增长量:基础增长速率 * 每150tick的间隔 * 甲壳增长速率系数
|
||||
float growthAmount = BaseChitinGainPerTick * 150f * GrowthRatePerTick;
|
||||
|
||||
// 应用增长
|
||||
CurLevel += growthAmount;
|
||||
|
||||
// 确保不超过最大值,不低于0
|
||||
float maxLevel = MaxLevel; // 计算一次并缓存
|
||||
if (CurLevel > maxLevel)
|
||||
CurLevel = maxLevel;
|
||||
else if (CurLevel < 0f)
|
||||
CurLevel = 0f;
|
||||
|
||||
// 定期更新Hediff(每60tick一次)
|
||||
if (currentTick - lastHediffUpdateTick >= HediffUpdateInterval)
|
||||
{
|
||||
UpdateChitinHediff();
|
||||
lastHediffUpdateTick = currentTick;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取ARA_Chitin_Shell身体部位的数量
|
||||
private int GetChitinShellPartCount()
|
||||
{
|
||||
// 使用缓存值(如果有效)
|
||||
if (cachedShellPartCount >= 0 && pawn != null && !pawn.Dead)
|
||||
{
|
||||
return cachedShellPartCount;
|
||||
}
|
||||
|
||||
// 重新计算
|
||||
UpdateCachedShellPartCount();
|
||||
return cachedShellPartCount;
|
||||
}
|
||||
|
||||
// 更新缓存的身体部位数量
|
||||
private void UpdateCachedShellPartCount()
|
||||
{
|
||||
if (pawn == null || pawn.Dead || pawn.RaceProps == null || pawn.RaceProps.body == null)
|
||||
{
|
||||
cachedShellPartCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算身体部位数量
|
||||
int count = 0;
|
||||
|
||||
// 方法1:从pawn的身体部位记录中查找
|
||||
foreach (BodyPartRecord part in pawn.RaceProps.body.AllParts)
|
||||
{
|
||||
if (part.def.defName == CHITIN_SHELL_PART_NAME)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// 方法2:如果找不到,检查Hediff中是否有甲壳(作为备用方法)
|
||||
if (count == 0 && pawn.health != null && pawn.health.hediffSet != null)
|
||||
{
|
||||
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
|
||||
{
|
||||
if (hediff.Part != null && hediff.Part.def != null &&
|
||||
hediff.Part.def.defName == CHITIN_SHELL_PART_NAME)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cachedShellPartCount = count;
|
||||
}
|
||||
|
||||
// 重新计算身体部位数量(当身体发生变化时调用)
|
||||
public void RecalculateShellPartCount()
|
||||
{
|
||||
UpdateCachedShellPartCount();
|
||||
}
|
||||
|
||||
// 更新甲壳Hediff
|
||||
private void UpdateChitinHediff()
|
||||
{
|
||||
if (Extension == null || Extension.hediff == null || pawn.Dead)
|
||||
return;
|
||||
|
||||
// 直接使用CurLevel作为严重性,但可以根据配置的范围进行调整
|
||||
float severity = CurLevel;
|
||||
|
||||
// 如果需要,可以应用范围限制
|
||||
FloatRange severityRange = Extension.severityRange;
|
||||
if (severity > severityRange.max)
|
||||
severity = severityRange.max;
|
||||
else if (severity < severityRange.min)
|
||||
severity = severityRange.min;
|
||||
|
||||
// 如果严重性为0或接近0,移除Hediff
|
||||
if (severity <= 0.001f)
|
||||
{
|
||||
RemoveChitinHediff();
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保Hediff存在
|
||||
EnsureChitinHediff();
|
||||
|
||||
// 设置严重性
|
||||
if (chitinHediff != null)
|
||||
{
|
||||
chitinHediff.Severity = severity;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保Hediff存在
|
||||
private void EnsureChitinHediff()
|
||||
{
|
||||
if (chitinHediff == null || chitinHediff.pawn != pawn)
|
||||
{
|
||||
// 移除旧的Hediff
|
||||
if (chitinHediff != null && chitinHediff.pawn == pawn)
|
||||
{
|
||||
pawn.health.RemoveHediff(chitinHediff);
|
||||
}
|
||||
|
||||
// 创建新的Hediff
|
||||
chitinHediff = HediffMaker.MakeHediff(Extension.hediff, pawn);
|
||||
pawn.health.AddHediff(chitinHediff);
|
||||
}
|
||||
}
|
||||
|
||||
// 移除Hediff
|
||||
private void RemoveChitinHediff()
|
||||
{
|
||||
if (chitinHediff != null && chitinHediff.pawn == pawn)
|
||||
{
|
||||
pawn.health.RemoveHediff(chitinHediff);
|
||||
chitinHediff = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 减少甲壳存量(例如受伤时)
|
||||
public void ReduceChitin(float amount)
|
||||
{
|
||||
CurLevel -= amount;
|
||||
if (CurLevel < 0f)
|
||||
CurLevel = 0f;
|
||||
|
||||
// 立即更新Hediff
|
||||
UpdateChitinHediff();
|
||||
}
|
||||
|
||||
// 强制清空甲壳
|
||||
public void EmptyChitin()
|
||||
{
|
||||
CurLevel = 0f;
|
||||
RemoveChitinHediff();
|
||||
}
|
||||
|
||||
// 重置到初始状态
|
||||
public override void SetInitialLevel()
|
||||
{
|
||||
// 初始为空
|
||||
CurLevel = 0f;
|
||||
RemoveChitinHediff();
|
||||
UpdateCachedShellPartCount();
|
||||
}
|
||||
|
||||
// 获取当前严重性
|
||||
public float GetCurrentSeverity()
|
||||
{
|
||||
if (chitinHediff == null)
|
||||
return 0f;
|
||||
|
||||
return chitinHediff.Severity;
|
||||
}
|
||||
|
||||
// 获取提示字符串
|
||||
public override string GetTipString()
|
||||
{
|
||||
string text = (LabelCap + ": " + CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor);
|
||||
text += "\n" + def.description;
|
||||
|
||||
int shellCount = GetChitinShellPartCount();
|
||||
text += $"\n{"ARA_Chitin.ShellParts".Translate()}: {shellCount}";
|
||||
|
||||
// 显示每秒增长速率(更直观)
|
||||
text += $"\n{"ARA_Chitin.GrowthRate".Translate()}: {GrowthRatePerSecond:0.#####}/ {"LetterSecond".Translate()}";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// 在UI上绘制
|
||||
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
|
||||
{
|
||||
// 确保阈值已设置
|
||||
if (threshPercents == null)
|
||||
{
|
||||
SetDefaultThresholds();
|
||||
}
|
||||
|
||||
base.DrawOnGUI(rect, maxThresholdMarkers, customMargin, false, doTooltip, rectForTooltip, drawLabel);
|
||||
}
|
||||
|
||||
// 是否冻结
|
||||
protected override bool IsFrozen
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果基础条件冻结,则甲壳生长也冻结
|
||||
if (base.IsFrozen)
|
||||
return true;
|
||||
|
||||
// 如果生物死亡,则冻结
|
||||
if (pawn.Dead)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// GUI变化箭头(总是显示增长)
|
||||
public override int GUIChangeArrow => 1;
|
||||
|
||||
// 调试调整百分比
|
||||
protected override void OffsetDebugPercent(float offsetPercent)
|
||||
{
|
||||
base.OffsetDebugPercent(offsetPercent);
|
||||
UpdateChitinHediff();
|
||||
}
|
||||
|
||||
// 当生物死亡时清理Hediff
|
||||
public void OnPawnDeath()
|
||||
{
|
||||
if (Extension?.removeOnDeath ?? true)
|
||||
{
|
||||
RemoveChitinHediff();
|
||||
}
|
||||
}
|
||||
|
||||
// 当生物重生时恢复Hediff
|
||||
public void OnPawnResurrected()
|
||||
{
|
||||
if (CurLevel > 0f && Extension?.hediff != null)
|
||||
{
|
||||
UpdateChitinHediff();
|
||||
}
|
||||
UpdateCachedShellPartCount();
|
||||
}
|
||||
|
||||
// 当身体部位发生变化时调用
|
||||
public void NotifyBodyPartChanged()
|
||||
{
|
||||
UpdateCachedShellPartCount();
|
||||
|
||||
// 如果最大容量减少,确保当前值不超过新最大值
|
||||
if (CurLevel > MaxLevel)
|
||||
{
|
||||
CurLevel = MaxLevel;
|
||||
UpdateChitinHediff();
|
||||
}
|
||||
}
|
||||
|
||||
public Comp_ChitinStripping GetStripComp()
|
||||
{
|
||||
if (pawn == null)
|
||||
return null;
|
||||
|
||||
return pawn.TryGetComp<Comp_ChitinStripping>();
|
||||
}
|
||||
// 获取是否可以剥离
|
||||
public bool CanStripChitin()
|
||||
{
|
||||
var stripComp = GetStripComp();
|
||||
if (stripComp == null)
|
||||
return false;
|
||||
|
||||
return stripComp.CanStripNow(pawn);
|
||||
}
|
||||
// 获取剥离信息字符串
|
||||
public string GetStripInfoString()
|
||||
{
|
||||
var stripComp = GetStripComp();
|
||||
if (stripComp == null)
|
||||
return "ARA_ChitinStripping_Disabled".Translate();
|
||||
|
||||
if (!stripComp.CanStripNow(pawn))
|
||||
{
|
||||
int cooldownTicks = stripComp.CooldownTicksRemaining;
|
||||
if (cooldownTicks > 0)
|
||||
{
|
||||
float cooldownSeconds = cooldownTicks / 60f;
|
||||
return "ARA_ChitinStripping_Cooldown".Translate(cooldownSeconds.ToString("F1"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return "ARA_ChitinStripping_Threshold".Translate((stripComp.StripThreshold * 100f).ToString("F0"));
|
||||
}
|
||||
}
|
||||
|
||||
return "ARA_ChitinStripping_Ready".Translate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,52 @@
|
||||
// File: Need_HoneyProduction.cs
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class HoneyProductionExtension : DefModExtension
|
||||
{
|
||||
// 蜜罐生产的基础转化率(相对于食物流失的百分比)
|
||||
public float baseConversionRate = 0.5f;
|
||||
|
||||
// 最大蜜罐容量(可选,覆盖默认值)
|
||||
public float maxHoneyCapacity = 1f;
|
||||
|
||||
// 是否启用蜜罐生产
|
||||
public bool enableHoneyProduction = true;
|
||||
|
||||
// 生产速率乘数(影响生产速度)
|
||||
public float productionSpeedFactor = 1f;
|
||||
|
||||
// 蜜罐类别对应的生产效率(可选,覆盖默认值)
|
||||
public float fullProductionEfficiency = 1.5f;
|
||||
public float highProductionEfficiency = 1.2f;
|
||||
public float mediumProductionEfficiency = 1f;
|
||||
public float lowProductionEfficiency = 0.5f;
|
||||
public float emptyProductionEfficiency = 0f;
|
||||
|
||||
// 生产间隔(ticks,可选覆盖默认值)
|
||||
public int productionInterval = 150;
|
||||
|
||||
public static HoneyProductionExtension Get(Pawn pawn)
|
||||
{
|
||||
if (pawn?.def?.GetModExtension<HoneyProductionExtension>() is HoneyProductionExtension ext)
|
||||
return ext;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取转化率
|
||||
public float GetConversionRate()
|
||||
{
|
||||
return baseConversionRate * productionSpeedFactor;
|
||||
}
|
||||
}
|
||||
|
||||
public class Need_HoneyProduction : Need
|
||||
{
|
||||
// 基础流失速率(与食物需要对应)
|
||||
private const float BaseHoneyGainPerTick = 2.6666667E-05f * 0.5f; // 食物流失速率的50%
|
||||
private const float BaseHoneyGainPerTick = 2.6666667E-05f * 0.5f; // 食物流失速率的50%作为默认值
|
||||
|
||||
// 用于存储对食物需要的引用
|
||||
private Need_Food cachedFoodNeed;
|
||||
@@ -18,8 +57,22 @@ namespace ArachnaeSwarm
|
||||
// 上次满的时间点
|
||||
private int lastFullTick = -99999;
|
||||
|
||||
// 蜜罐的最大容量(可能需要调整)
|
||||
public override float MaxLevel => 1f;
|
||||
// 缓存的ModExtension
|
||||
private HoneyProductionExtension cachedExtension;
|
||||
|
||||
// 蜜罐的最大容量 - 优先使用ModExtension的值
|
||||
public override float MaxLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
var ext = GetExtension();
|
||||
if (ext != null && ext.maxHoneyCapacity > 0)
|
||||
{
|
||||
return ext.maxHoneyCapacity;
|
||||
}
|
||||
return FoodNeed?.MaxLevel ?? 1f;
|
||||
}
|
||||
}
|
||||
|
||||
// 当前类别
|
||||
public HoneyProductionCategory CurCategory => curCategoryInt;
|
||||
@@ -35,6 +88,29 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
get
|
||||
{
|
||||
var ext = GetExtension();
|
||||
|
||||
// 如果有扩展定义,使用扩展的值
|
||||
if (ext != null)
|
||||
{
|
||||
switch (curCategoryInt)
|
||||
{
|
||||
case HoneyProductionCategory.Full:
|
||||
return ext.fullProductionEfficiency;
|
||||
case HoneyProductionCategory.High:
|
||||
return ext.highProductionEfficiency;
|
||||
case HoneyProductionCategory.Medium:
|
||||
return ext.mediumProductionEfficiency;
|
||||
case HoneyProductionCategory.Low:
|
||||
return ext.lowProductionEfficiency;
|
||||
case HoneyProductionCategory.Empty:
|
||||
return ext.emptyProductionEfficiency;
|
||||
default:
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认值
|
||||
switch (curCategoryInt)
|
||||
{
|
||||
case HoneyProductionCategory.Full:
|
||||
@@ -53,12 +129,32 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// 获取扩展
|
||||
private HoneyProductionExtension GetExtension()
|
||||
{
|
||||
if (cachedExtension == null && pawn != null)
|
||||
{
|
||||
cachedExtension = pawn.def?.GetModExtension<HoneyProductionExtension>();
|
||||
}
|
||||
return cachedExtension;
|
||||
}
|
||||
|
||||
// 是否启用蜜罐生产
|
||||
private bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
var ext = GetExtension();
|
||||
return ext == null || ext.enableHoneyProduction; // 默认启用
|
||||
}
|
||||
}
|
||||
|
||||
// 获取食物需要的引用
|
||||
private Need_Food FoodNeed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedFoodNeed == null || cachedFoodNeed.pawn != pawn)
|
||||
if (cachedFoodNeed == null)
|
||||
{
|
||||
cachedFoodNeed = pawn.needs?.TryGetNeed<Need_Food>();
|
||||
}
|
||||
@@ -86,7 +182,9 @@ namespace ArachnaeSwarm
|
||||
|
||||
public override void NeedInterval()
|
||||
{
|
||||
base.NeedInterval();
|
||||
// 如果不启用,直接返回
|
||||
if (!IsEnabled)
|
||||
return;
|
||||
|
||||
// 检查是否需要冻结(与食物需要类似的条件)
|
||||
if (IsFrozen)
|
||||
@@ -97,11 +195,21 @@ namespace ArachnaeSwarm
|
||||
// 获取食物需要的流失速率
|
||||
float foodFallRate = GetFoodFallRate();
|
||||
|
||||
// 蜜罐的增长速率是食物流失速率的50%
|
||||
float honeyGainRate = foodFallRate * 0.5f;
|
||||
// 获取转化率(从ModExtension或使用默认值)
|
||||
float conversionRate = GetExtension()?.GetConversionRate() ?? 0.5f;
|
||||
|
||||
// 应用150 ticks的间隔
|
||||
CurLevel += honeyGainRate * 150f;
|
||||
// 蜜罐的增长速率 = 食物流失速率 × 转化率
|
||||
float honeyGainRate = foodFallRate * conversionRate;
|
||||
|
||||
// 获取生产间隔
|
||||
int interval = GetExtension()?.productionInterval ?? 150;
|
||||
|
||||
// 应用间隔
|
||||
CurLevel += honeyGainRate * interval;
|
||||
|
||||
// 确保不超过最大容量
|
||||
if (CurLevel > MaxLevel)
|
||||
CurLevel = MaxLevel;
|
||||
|
||||
// 更新类别
|
||||
UpdateCategory();
|
||||
@@ -172,15 +280,39 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
string text = (LabelCap + ": " + CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor);
|
||||
text += "\n" + def.description;
|
||||
text += $"\n\n{"AS.HoneyProduction.CurrentLevel".Translate()}: {CurLevel:0.##} / {MaxLevel:0.##}";
|
||||
text += $"\n{"AS.HoneyProduction.Category".Translate()}: {GetCategoryLabel().CapitalizeFirst()}";
|
||||
text += $"\n{"AS.HoneyProduction.Efficiency".Translate()}: {ProductionEfficiency.ToStringPercent()}";
|
||||
text += $"\n{"AS.HoneyProduction.FoodDrainRate".Translate()}: {GetFoodFallRate():0.#####}/tick";
|
||||
text += $"\n{"AS.HoneyProduction.HoneyGainRate".Translate()}: {(GetFoodFallRate() * 0.5f):0.#####}/tick";
|
||||
text += $"\n{"ARA_HoneyProduction.Efficiency".Translate()} {ProductionEfficiency.ToStringPercent()}";
|
||||
|
||||
// 获取每tick的速率
|
||||
float foodFallPerTick = GetFoodFallRate();
|
||||
float conversionRate = GetExtension()?.GetConversionRate() ?? 0.5f;
|
||||
float honeyGainPerTick = foodFallPerTick * conversionRate;
|
||||
|
||||
// 转换为每秒:1秒 = 60tick
|
||||
float foodFallPerSecond = foodFallPerTick * 60f;
|
||||
float honeyGainPerSecond = honeyGainPerTick * 60f;
|
||||
|
||||
text += $"\n{"ARA_HoneyProduction.FoodDrainRate".Translate()}: {foodFallPerSecond:0.#####}/ {"LetterSecond".Translate()}";
|
||||
text += $"\n{"ARA_HoneyProduction.HoneyGainRate".Translate()}: {honeyGainPerSecond:0.#####}/ {"LetterSecond".Translate()}";
|
||||
|
||||
// 显示转化率信息
|
||||
if (GetExtension() != null)
|
||||
{
|
||||
text += $"\n{"ARA_HoneyProduction.ConversionRate".Translate()}: {conversionRate:P1}";
|
||||
if (GetExtension().productionSpeedFactor != 1f)
|
||||
{
|
||||
text += $"\n{"ARA_HoneyProduction.SpeedFactor".Translate()}: {GetExtension().productionSpeedFactor:F2}";
|
||||
}
|
||||
}
|
||||
|
||||
if (IsFull)
|
||||
{
|
||||
text += $"\n\n{"AS.HoneyProduction.FullWarning".Translate()}";
|
||||
text += $"\n\n{"ARA_HoneyProduction.FullWarning".Translate()}";
|
||||
}
|
||||
|
||||
// 显示是否启用
|
||||
if (!IsEnabled)
|
||||
{
|
||||
text += $"\n\n<color=orange>{"ARA_HoneyProduction.Disabled".Translate()}</color>";
|
||||
}
|
||||
|
||||
return text;
|
||||
@@ -192,15 +324,15 @@ namespace ArachnaeSwarm
|
||||
switch (curCategoryInt)
|
||||
{
|
||||
case HoneyProductionCategory.Full:
|
||||
return "AS.HoneyProduction.Full".Translate();
|
||||
return "ARA_HoneyProduction.Full".Translate();
|
||||
case HoneyProductionCategory.High:
|
||||
return "AS.HoneyProduction.High".Translate();
|
||||
return "ARA_HoneyProduction.High".Translate();
|
||||
case HoneyProductionCategory.Medium:
|
||||
return "AS.HoneyProduction.Medium".Translate();
|
||||
return "ARA_HoneyProduction.Medium".Translate();
|
||||
case HoneyProductionCategory.Low:
|
||||
return "AS.HoneyProduction.Low".Translate();
|
||||
return "ARA_HoneyProduction.Low".Translate();
|
||||
case HoneyProductionCategory.Empty:
|
||||
return "AS.HoneyProduction.Empty".Translate();
|
||||
return "ARA_HoneyProduction.Empty".Translate();
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -209,6 +341,10 @@ namespace ArachnaeSwarm
|
||||
// 在UI上绘制
|
||||
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
|
||||
{
|
||||
// 如果不启用,不显示
|
||||
if (!IsEnabled)
|
||||
return;
|
||||
|
||||
if (threshPercents == null)
|
||||
{
|
||||
threshPercents = new System.Collections.Generic.List<float>
|
||||
@@ -229,10 +365,6 @@ namespace ArachnaeSwarm
|
||||
if (base.IsFrozen)
|
||||
return true;
|
||||
|
||||
// 如果没有食物需要,或者食物需要被冻结,则蜜罐生产也冻结
|
||||
if (FoodNeed == null || FoodNeed.IsFrozen)
|
||||
return true;
|
||||
|
||||
// 如果生物死亡,则冻结
|
||||
if (pawn.Dead)
|
||||
return true;
|
||||
@@ -242,7 +374,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
// GUI变化箭头(总是显示增长)
|
||||
public override int GUIChangeArrow => 1;
|
||||
public override int GUIChangeArrow => IsEnabled ? 1 : 0;
|
||||
|
||||
// 调试调整百分比
|
||||
protected override void OffsetDebugPercent(float offsetPercent)
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace ArachnaeSwarm
|
||||
// 尝试加载图标,如果失败则使用默认图标
|
||||
try
|
||||
{
|
||||
toggleCommand.icon = ContentFinder<Texture2D>.Get("Wula/UI/Commands/WULA_ShowRadius", false);
|
||||
toggleCommand.icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Commands/ARA_ShowRadius", false);
|
||||
if (toggleCommand.icon == null)
|
||||
{
|
||||
// 使用一个简单的占位符图标
|
||||
|
||||
BIN
非公开资源/Content/Textures/UI/Commands/ARA_CallLarva.sai2
Normal file
BIN
非公开资源/Content/Textures/UI/Commands/ARA_CallLarva.sai2
Normal file
Binary file not shown.
BIN
非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2
Normal file
BIN
非公开资源/Content/Textures/UI/Commands/ARA_StripChitin.sai2
Normal file
Binary file not shown.
Reference in New Issue
Block a user