1
This commit is contained in:
Binary file not shown.
@@ -24,6 +24,12 @@
|
|||||||
<!-- 易燃性 -->
|
<!-- 易燃性 -->
|
||||||
<Flammability>0.05</Flammability>
|
<Flammability>0.05</Flammability>
|
||||||
</statFactors>
|
</statFactors>
|
||||||
|
<capMods>
|
||||||
|
<li>
|
||||||
|
<capacity>Consciousness</capacity>
|
||||||
|
<offset>0.25</offset>
|
||||||
|
</li>
|
||||||
|
</capMods>
|
||||||
<!-- 免疫非纳米机械疾病 -->
|
<!-- 免疫非纳米机械疾病 -->
|
||||||
<makeImmuneTo>
|
<makeImmuneTo>
|
||||||
<li>Flu</li>
|
<li>Flu</li>
|
||||||
@@ -38,6 +44,7 @@
|
|||||||
</makeImmuneTo>
|
</makeImmuneTo>
|
||||||
<enablesNeeds>
|
<enablesNeeds>
|
||||||
<li>WULA_Energy</li>
|
<li>WULA_Energy</li>
|
||||||
|
<li>WULA_MaintenanceNeed</li>
|
||||||
</enablesNeeds>
|
</enablesNeeds>
|
||||||
<disablesNeeds>
|
<disablesNeeds>
|
||||||
<li>Food</li>
|
<li>Food</li>
|
||||||
@@ -45,6 +52,11 @@
|
|||||||
</disablesNeeds>
|
</disablesNeeds>
|
||||||
</li>
|
</li>
|
||||||
</stages>
|
</stages>
|
||||||
|
<comps>
|
||||||
|
<li Class="WulaFallenEmpire.HediffCompProperties_MaintenanceDamage">
|
||||||
|
<damageToMaintenanceFactor>0.0025</damageToMaintenanceFactor> <!-- 1点伤害 = 0.25%维护度减少 -->
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
</HediffDef>
|
</HediffDef>
|
||||||
<HediffDef>
|
<HediffDef>
|
||||||
<defName>WULA_ChargingHediff</defName>
|
<defName>WULA_ChargingHediff</defName>
|
||||||
@@ -68,73 +80,67 @@
|
|||||||
</li>
|
</li>
|
||||||
</stages>
|
</stages>
|
||||||
</HediffDef>
|
</HediffDef>
|
||||||
|
|
||||||
<HediffDef>
|
<HediffDef>
|
||||||
<defName>WULA_Maintenance_Neglect</defName>
|
<defName>WULA_Maintenance_MinorBreakdown</defName>
|
||||||
<label>维护</label>
|
<label>维护</label>
|
||||||
<description>乌拉帝国的合成人因为设计的过于繁琐,导致需要频繁维护。当她们处于良好维护状态时,各方面的能力都会有所上升,反之如果常年得不到维护或是短时间受到大量伤害,则其将变得难以自主运行甚至直接停机!</description>
|
<description>这台乌拉帝国合成人已经在环境恶劣的边缘世界活跃了一段时间,尽管总体状态良好但是已经有了一些小瑕疵。</description>
|
||||||
<hediffClass>Hediff_High</hediffClass>
|
<hediffClass>Hediff_High</hediffClass>
|
||||||
<defaultLabelColor>(0.8, 0.35, 0.35)</defaultLabelColor>
|
<defaultLabelColor>(0.8, 0.35, 0.35)</defaultLabelColor>
|
||||||
<isBad>false</isBad>
|
<isBad>false</isBad>
|
||||||
<initialSeverity>0</initialSeverity>
|
<minSeverity>0.1</minSeverity>
|
||||||
<minSeverity>0</minSeverity>
|
<initialSeverity>0.5</initialSeverity>
|
||||||
<maxSeverity>2.0</maxSeverity>
|
<maxSeverity>1.0</maxSeverity>
|
||||||
<!--<lethalSeverity>2</lethalSeverity>-->
|
|
||||||
<comps>
|
|
||||||
<li Class="WulaFallenEmpire.HediffCompProperties_MaintenanceNeed">
|
|
||||||
<thresholdDays>60</thresholdDays>
|
|
||||||
<!-- 60天内严重性达到1.0 (1.0 / 60 = 0.0166) -->
|
|
||||||
<severityPerDayBeforeThreshold>0.0166</severityPerDayBeforeThreshold>
|
|
||||||
<!-- 达到阈值后,在30天内从1.0增长到2.0 (1.0 / 30 ≈ 0.03333) -->
|
|
||||||
<severityPerDayAfterThreshold>0.03333</severityPerDayAfterThreshold>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.HediffCompProperties_DamageResponse">
|
|
||||||
<severityIncreasePerDamage>0.005</severityIncreasePerDamage>
|
|
||||||
</li>
|
|
||||||
</comps>
|
|
||||||
<stages>
|
<stages>
|
||||||
<li>
|
<li>
|
||||||
<label>极佳</label>
|
<label>轻微损坏</label>
|
||||||
<minSeverity>0</minSeverity>
|
<minSeverity>0</minSeverity>
|
||||||
<capMods>
|
<capMods>
|
||||||
<li>
|
<li>
|
||||||
<capacity>Consciousness</capacity>
|
<capacity>Consciousness</capacity>
|
||||||
<offset>0.1</offset>
|
<offset>-0.25</offset>
|
||||||
</li>
|
|
||||||
</capMods>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label>稳定</label>
|
|
||||||
<minSeverity>0.5</minSeverity>
|
|
||||||
<capMods>
|
|
||||||
<li>
|
|
||||||
<capacity>Consciousness</capacity>
|
|
||||||
<offset>0</offset>
|
|
||||||
</li>
|
|
||||||
</capMods>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label>需要</label>
|
|
||||||
<minSeverity>0.75</minSeverity>
|
|
||||||
<capMods>
|
|
||||||
<li>
|
|
||||||
<capacity>Consciousness</capacity>
|
|
||||||
<offset>-0.20</offset>
|
|
||||||
</li>
|
</li>
|
||||||
</capMods>
|
</capMods>
|
||||||
</li>
|
</li>
|
||||||
|
</stages>
|
||||||
|
</HediffDef>
|
||||||
|
<HediffDef>
|
||||||
|
<defName>WULA_Maintenance_MajorBreakdown</defName>
|
||||||
|
<label>维护</label>
|
||||||
|
<description>这台乌拉帝国合成人有一段时间没有进行维护了,运行起来相当吃力。</description>
|
||||||
|
<hediffClass>Hediff_High</hediffClass>
|
||||||
|
<defaultLabelColor>(0.8, 0.35, 0.35)</defaultLabelColor>
|
||||||
|
<isBad>false</isBad>
|
||||||
|
<minSeverity>0.1</minSeverity>
|
||||||
|
<initialSeverity>0.5</initialSeverity>
|
||||||
|
<maxSeverity>1.0</maxSeverity>
|
||||||
|
<stages>
|
||||||
<li>
|
<li>
|
||||||
<label>损坏</label>
|
<label>损坏</label>
|
||||||
<minSeverity>1.0</minSeverity>
|
<minSeverity>0</minSeverity>
|
||||||
<capMods>
|
<capMods>
|
||||||
<li>
|
<li>
|
||||||
<capacity>Consciousness</capacity>
|
<capacity>Consciousness</capacity>
|
||||||
<setMax>0.5</setMax>
|
<offset>-0.25</offset>
|
||||||
</li>
|
</li>
|
||||||
</capMods>
|
</capMods>
|
||||||
</li>
|
</li>
|
||||||
|
</stages>
|
||||||
|
</HediffDef>
|
||||||
|
<HediffDef>
|
||||||
|
<defName>WULA_Maintenance_CriticalFailuren</defName>
|
||||||
|
<label>维护</label>
|
||||||
|
<description>这台乌拉帝国合成人几乎无法运作了,需要立刻进行维护,否则就只是一堆废铁。</description>
|
||||||
|
<hediffClass>Hediff_High</hediffClass>
|
||||||
|
<defaultLabelColor>(0.8, 0.35, 0.35)</defaultLabelColor>
|
||||||
|
<isBad>false</isBad>
|
||||||
|
<minSeverity>0.1</minSeverity>
|
||||||
|
<initialSeverity>0.5</initialSeverity>
|
||||||
|
<maxSeverity>1.0</maxSeverity>
|
||||||
|
<stages>
|
||||||
<li>
|
<li>
|
||||||
<label>崩坏</label>
|
<label>崩坏</label>
|
||||||
<minSeverity>2.0</minSeverity>
|
<minSeverity>0</minSeverity>
|
||||||
<capMods>
|
<capMods>
|
||||||
<li>
|
<li>
|
||||||
<capacity>Consciousness</capacity>
|
<capacity>Consciousness</capacity>
|
||||||
@@ -321,9 +327,9 @@
|
|||||||
<activeSeverity>0.5</activeSeverity>
|
<activeSeverity>0.5</activeSeverity>
|
||||||
<inactiveSeverity>1.5</inactiveSeverity>
|
<inactiveSeverity>1.5</inactiveSeverity>
|
||||||
<minEnergyThreshold>0.1</minEnergyThreshold>
|
<minEnergyThreshold>0.1</minEnergyThreshold>
|
||||||
<repairCostPerHP>0.01</repairCostPerHP>
|
<repairCostPerHP>0.02</repairCostPerHP>
|
||||||
<repairCooldownAfterDamage>1200</repairCooldownAfterDamage>
|
<repairCooldownAfterDamage>600</repairCooldownAfterDamage>
|
||||||
</li>
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
</HediffDef>
|
</HediffDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -29,5 +29,4 @@
|
|||||||
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||||
<casualInterruptible>false</casualInterruptible>
|
<casualInterruptible>false</casualInterruptible>
|
||||||
</JobDef>
|
</JobDef>
|
||||||
|
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -23,4 +23,28 @@
|
|||||||
</li>
|
</li>
|
||||||
</modExtensions>
|
</modExtensions>
|
||||||
</NeedDef>
|
</NeedDef>
|
||||||
|
<!-- 维护需求定义 -->
|
||||||
|
<NeedDef>
|
||||||
|
<defName>WULA_MaintenanceNeed</defName>
|
||||||
|
<label>维护</label>
|
||||||
|
<needClass>WulaFallenEmpire.Need_Maintenance</needClass>
|
||||||
|
<description>乌拉帝国的合成人因为设计的过于繁琐,导致需要频繁维护。当她们处于良好维护状态时,各方面的能力都会有所上升,反之如果常年得不到维护或是短时间受到大量伤害,则其将变得难以自主运行甚至直接停机!</description>
|
||||||
|
<major>true</major>
|
||||||
|
<onlyIfCausedByHediff>true</onlyIfCausedByHediff>
|
||||||
|
<listPriority>799</listPriority>
|
||||||
|
<showOnNeedList>true</showOnNeedList>
|
||||||
|
<freezeWhileSleeping>false</freezeWhileSleeping>
|
||||||
|
<freezeInMentalState>false</freezeInMentalState>
|
||||||
|
<modExtensions>
|
||||||
|
<li Class="WulaFallenEmpire.MaintenanceNeedExtension">
|
||||||
|
<severityPerDayBeforeThreshold>0.05</severityPerDayBeforeThreshold> <!-- 严重退化前的速率 -->
|
||||||
|
<severityPerDayAfterThreshold>0.1</severityPerDayAfterThreshold> <!-- 严重退化前的速率 -->
|
||||||
|
<thresholdDays>5</thresholdDays> <!-- 严重退化预期天数 -->
|
||||||
|
<maintenanceWorkType>PatientBedRest</maintenanceWorkType>
|
||||||
|
<minorBreakdownHediff>WULA_Maintenance_MinorBreakdown</minorBreakdownHediff>
|
||||||
|
<majorBreakdownHediff>WULA_Maintenance_MajorBreakdown</majorBreakdownHediff>
|
||||||
|
<criticalFailureHediff>WULA_Maintenance_CriticalFailuren</criticalFailureHediff>
|
||||||
|
</li>
|
||||||
|
</modExtensions>
|
||||||
|
</NeedDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
|
|||||||
@@ -147,9 +147,6 @@
|
|||||||
<destroySound>BuildingDestroyed_Metal_Small</destroySound>
|
<destroySound>BuildingDestroyed_Metal_Small</destroySound>
|
||||||
<turretBurstCooldownTime>3.5</turretBurstCooldownTime>
|
<turretBurstCooldownTime>3.5</turretBurstCooldownTime>
|
||||||
</building>
|
</building>
|
||||||
<thingCategories>
|
|
||||||
<li>BuildingsMisc</li>
|
|
||||||
</thingCategories>
|
|
||||||
<comps>
|
<comps>
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MechanoidRecycler">
|
<li Class="WulaFallenEmpire.CompProperties_MechanoidRecycler">
|
||||||
<maxStorageCapacity>6</maxStorageCapacity>
|
<maxStorageCapacity>6</maxStorageCapacity>
|
||||||
@@ -230,4 +227,84 @@
|
|||||||
</li>
|
</li>
|
||||||
</verbs>
|
</verbs>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
|
<!-- 制造机 -->
|
||||||
|
<ThingDef ParentName="BenchBase">
|
||||||
|
<defName>WULA_Cube_Productor_BIO</defName>
|
||||||
|
<label>乌拉帝国编织体(生物能)</label>
|
||||||
|
<description>一台仿制乌拉帝国科技而建造的塑性构造体,不仅要消耗大量木头用以提供生物能,还只能生产基础的衣物和能源核心用以维持生存——不过它很轻,可以随探险队一起移动。</description>
|
||||||
|
<thingClass>WulaFallenEmpire.Building_GlobalWorkTable</thingClass>
|
||||||
|
<drawerType>MapMeshAndRealTime</drawerType>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Wula/Building/WULA_Cube_Productor_BIO</texPath>
|
||||||
|
<graphicClass>Graphic_Multi</graphicClass>
|
||||||
|
<drawSize>(1,1)</drawSize>
|
||||||
|
<damageData>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</damageData>
|
||||||
|
<shadowData>
|
||||||
|
<volume>(0.75, 0.75, 0.5)</volume>
|
||||||
|
</shadowData>
|
||||||
|
</graphicData>
|
||||||
|
<constructEffect>ConstructMetal</constructEffect>
|
||||||
|
<costList>
|
||||||
|
<Steel>50</Steel>
|
||||||
|
</costList>
|
||||||
|
<altitudeLayer>Building</altitudeLayer>
|
||||||
|
<castEdgeShadows>false</castEdgeShadows>
|
||||||
|
<fillPercent>0.5</fillPercent>
|
||||||
|
<useHitPoints>True</useHitPoints>
|
||||||
|
<statBases>
|
||||||
|
<Mass>5</Mass>
|
||||||
|
<WorkToBuild>2000</WorkToBuild>
|
||||||
|
<MaxHitPoints>180</MaxHitPoints>
|
||||||
|
<Flammability>1.0</Flammability>
|
||||||
|
<WorkTableWorkSpeedFactor>0.5</WorkTableWorkSpeedFactor>
|
||||||
|
</statBases>
|
||||||
|
<size>(1,1)</size>
|
||||||
|
<designationCategory>WULA_Buildings</designationCategory>
|
||||||
|
<uiOrder>2120</uiOrder>
|
||||||
|
<passability>PassThroughOnly</passability>
|
||||||
|
<pathCost>50</pathCost>
|
||||||
|
<hasInteractionCell>True</hasInteractionCell>
|
||||||
|
<interactionCellOffset>(0,0,-1)</interactionCellOffset>
|
||||||
|
<surfaceType>Item</surfaceType>
|
||||||
|
<researchPrerequisites>
|
||||||
|
<li>WULA_Base_Technology</li>
|
||||||
|
</researchPrerequisites>
|
||||||
|
<!-- 可用配方 -->
|
||||||
|
<recipes>
|
||||||
|
<li>Make_WULA_Charge_Cube</li>
|
||||||
|
<li>Recharge_WULA_Charge_Cube</li>
|
||||||
|
<li MayRequire="Ludeon.RimWorld.Anomaly">Wula_Make_Zro</li>
|
||||||
|
</recipes>
|
||||||
|
<inspectorTabs>
|
||||||
|
<li>WulaFallenEmpire.ITab_GlobalBills</li>
|
||||||
|
</inspectorTabs>
|
||||||
|
<comps>
|
||||||
|
<li Class="CompProperties_Refuelable">
|
||||||
|
<fuelConsumptionRate>300.0</fuelConsumptionRate>
|
||||||
|
<fuelCapacity>150.0</fuelCapacity>
|
||||||
|
<fuelFilter>
|
||||||
|
<thingDefs>
|
||||||
|
<li>WoodLog</li>
|
||||||
|
</thingDefs>
|
||||||
|
</fuelFilter>
|
||||||
|
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||||
|
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_HeatPusher">
|
||||||
|
<compClass>CompHeatPusherPowered</compClass>
|
||||||
|
<heatPerSecond>4</heatPerSecond>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
<placeWorkers>
|
||||||
|
<li>PlaceWorker_PreventInteractionSpotOverlap</li>
|
||||||
|
</placeWorkers>
|
||||||
|
<building>
|
||||||
|
<!-- <isMealSource>true</isMealSource> -->
|
||||||
|
<spawnedConceptLearnOpportunity>BillsTab</spawnedConceptLearnOpportunity>
|
||||||
|
<heatPerTickWhileWorking>0.10</heatPerTickWhileWorking>
|
||||||
|
</building>
|
||||||
|
</ThingDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -807,18 +807,20 @@
|
|||||||
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
||||||
</li>
|
</li>
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MaintenancePod">
|
<li Class="WulaFallenEmpire.CompProperties_MaintenancePod">
|
||||||
<baseDurationTicks>30000</baseDurationTicks> <!-- Merged from user feedback -->
|
|
||||||
<ticksPerSeverity>150000</ticksPerSeverity> <!-- Kept from previous change -->
|
|
||||||
<powerConsumptionRunning>500</powerConsumptionRunning>
|
|
||||||
<powerConsumptionIdle>25</powerConsumptionIdle>
|
|
||||||
<hediffToRemove>WULA_Maintenance_Neglect</hediffToRemove>
|
|
||||||
<componentCostPerSeverity>2</componentCostPerSeverity> <!-- 5 components per 100% severity -->
|
|
||||||
<baseComponentCost>1</baseComponentCost>
|
|
||||||
<!-- <minSeverityToMaintain>0.75</minSeverityToMaintain> -->
|
|
||||||
<hediffSeverityAfterCycle>0.01</hediffSeverityAfterCycle>
|
|
||||||
<enterSound>BiosculpterPod_Enter</enterSound>
|
<enterSound>BiosculpterPod_Enter</enterSound>
|
||||||
<exitSound>BiosculpterPod_Exit</exitSound>
|
<exitSound>BiosculpterPod_Exit</exitSound>
|
||||||
<operatingEffecter>BiosculpterPod_Operating</operatingEffecter>
|
<operatingEffecter>BiosculpterPod_Operating</operatingEffecter>
|
||||||
|
<baseDurationTicks>30000</baseDurationTicks> <!-- 1天 -->
|
||||||
|
<ticksPerNeedLevel>150000</ticksPerNeedLevel> <!-- 每降低1点需求需要2天 -->
|
||||||
|
<powerConsumptionRunning>500</powerConsumptionRunning>
|
||||||
|
<powerConsumptionIdle>25</powerConsumptionIdle>
|
||||||
|
<componentCostPerNeedLevel>2</componentCostPerNeedLevel>
|
||||||
|
<baseComponentCost>1</baseComponentCost>
|
||||||
|
<minNeedLevelToMaintain>0.3</minNeedLevelToMaintain>
|
||||||
|
<needLevelAfterCycle>1.0</needLevelAfterCycle>
|
||||||
|
<healInjuries>true</healInjuries>
|
||||||
|
<healMissingParts>true</healMissingParts>
|
||||||
|
<maxInjuriesHealedPerCycle>5</maxInjuriesHealedPerCycle>
|
||||||
</li>
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
<placeWorkers>
|
<placeWorkers>
|
||||||
|
|||||||
@@ -664,7 +664,7 @@
|
|||||||
<!-- 血液,不流血 -->
|
<!-- 血液,不流血 -->
|
||||||
<bloodDef>Filth_MachineBits</bloodDef>
|
<bloodDef>Filth_MachineBits</bloodDef>
|
||||||
<!-- 基础血量 -->
|
<!-- 基础血量 -->
|
||||||
<baseHealthScale>1</baseHealthScale>
|
<baseHealthScale>1.2</baseHealthScale>
|
||||||
<!-- 解剖产物 -->
|
<!-- 解剖产物 -->
|
||||||
<leatherDef>Steel</leatherDef>
|
<leatherDef>Steel</leatherDef>
|
||||||
<specificMeatDef>Steel</specificMeatDef>
|
<specificMeatDef>Steel</specificMeatDef>
|
||||||
|
|||||||
@@ -110,4 +110,16 @@
|
|||||||
</modExtensions>
|
</modExtensions>
|
||||||
</WorkGiverDef>
|
</WorkGiverDef>
|
||||||
|
|
||||||
|
<!-- 维护工作 -->
|
||||||
|
<WorkGiverDef>
|
||||||
|
<defName>WULA_DoMaintenanceWork</defName>
|
||||||
|
<workType>PatientBedRest</workType>
|
||||||
|
<giverClass>WulaFallenEmpire.WorkGiver_DoMaintenance</giverClass>
|
||||||
|
<priorityInType>100</priorityInType>
|
||||||
|
<verb>接受维护于</verb>
|
||||||
|
<gerund>接受维护于</gerund>
|
||||||
|
<emergency>false</emergency>
|
||||||
|
<scanCells>true</scanCells>
|
||||||
|
<directOrderable>true</directOrderable>
|
||||||
|
</WorkGiverDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -92,4 +92,68 @@
|
|||||||
<WULA_RoofBlockingDesc>该空投地点顶部有屋顶,无法进行空投</WULA_RoofBlockingDesc>
|
<WULA_RoofBlockingDesc>该空投地点顶部有屋顶,无法进行空投</WULA_RoofBlockingDesc>
|
||||||
<WULA_BlockedByThickRoof>被厚岩顶阻挡</WULA_BlockedByThickRoof>
|
<WULA_BlockedByThickRoof>被厚岩顶阻挡</WULA_BlockedByThickRoof>
|
||||||
<WULA_BlockedByRoof>被屋顶阻挡</WULA_BlockedByRoof>
|
<WULA_BlockedByRoof>被屋顶阻挡</WULA_BlockedByRoof>
|
||||||
|
|
||||||
|
<!-- 维护舱状态 -->
|
||||||
|
<WULA_MaintenancePod_Status>维护舱状态</WULA_MaintenancePod_Status>
|
||||||
|
<WULA_MaintenancePod_State_Idle>空闲</WULA_MaintenancePod_State_Idle>
|
||||||
|
<WULA_MaintenancePod_State_Running>运行中</WULA_MaintenancePod_State_Running>
|
||||||
|
|
||||||
|
<!-- 维护舱交互 -->
|
||||||
|
<WULA_MaintenancePod_Enter>进入维护舱</WULA_MaintenancePod_Enter>
|
||||||
|
<WULA_MaintenancePod_EnterDesc>选择需要维护的合成人</WULA_MaintenancePod_EnterDesc>
|
||||||
|
<WULA_MaintenancePod_CancelDesc>取消当前维护周期</WULA_MaintenancePod_CancelDesc>
|
||||||
|
<WULA_MaintenancePod_NoOneNeeds>没有合成人需要维护</WULA_MaintenancePod_NoOneNeeds>
|
||||||
|
<WULA_MaintenancePod_NotEnoughComponents>需要 {0} 个零部件</WULA_MaintenancePod_NotEnoughComponents>
|
||||||
|
|
||||||
|
<!-- 维护效果消息 -->
|
||||||
|
<WULA_MaintenanceLevel>维护水平</WULA_MaintenanceLevel>
|
||||||
|
<WULA_MaintenanceCycleStarted>{0} 开始维护周期</WULA_MaintenanceCycleStarted>
|
||||||
|
<WULA_MaintenanceCycleComplete>{0} 维护完成</WULA_MaintenanceCycleComplete>
|
||||||
|
<WULA_MaintenanceHealedInjuries>修复了 {0} 的 {1} 处损伤</WULA_MaintenanceHealedInjuries>
|
||||||
|
<WULA_MaintenanceHealedParts>修复了 {0} 的缺失部位</WULA_MaintenanceHealedParts>
|
||||||
|
<WULA_MaintenanceCanceled>维护已取消</WULA_MaintenanceCanceled>
|
||||||
|
<WULA_NoHaulerAvailable>没有可用的搬运者</WULA_NoHaulerAvailable>
|
||||||
|
<WULA_NoMaintenanceNeed>无维护需求</WULA_NoMaintenanceNeed>
|
||||||
|
|
||||||
|
<!-- 维护需求相关 -->
|
||||||
|
<WULA_MaintenanceNeed>维护需求</WULA_MaintenanceNeed>
|
||||||
|
<WULA_MaintenanceStatus>状态: {0} (上次维护: {1}天前)</WULA_MaintenanceStatus>
|
||||||
|
<WULA_DegradationRate>退化速率: {0}/天</WULA_DegradationRate>
|
||||||
|
<WULA_MaintenanceCompleted>{0} 的维护已完成</WULA_MaintenanceCompleted>
|
||||||
|
|
||||||
|
<!-- 维护状态 -->
|
||||||
|
<WULA_Operational>运行正常</WULA_Operational>
|
||||||
|
<WULA_MinorBreakdown>轻微故障</WULA_MinorBreakdown>
|
||||||
|
<WULA_MajorBreakdown>严重故障</WULA_MajorBreakdown>
|
||||||
|
<WULA_CriticalFailure>完全故障</WULA_CriticalFailure>
|
||||||
|
|
||||||
|
<WULA_OperationalDesc>合成人运行在最佳状态</WULA_OperationalDesc>
|
||||||
|
<WULA_MinorBreakdownDesc>合成人出现轻微故障,工作效率降低</WULA_MinorBreakdownDesc>
|
||||||
|
<WULA_MajorBreakdownDesc>合成人出现严重故障,需要立即维护</WULA_MajorBreakdownDesc>
|
||||||
|
<WULA_CriticalFailureDesc>合成人完全故障,无法工作</WULA_CriticalFailureDesc>
|
||||||
|
|
||||||
|
<!-- 工作相关 -->
|
||||||
|
<WULA_SynthMaintenance>合成人维护</WULA_SynthMaintenance>
|
||||||
|
<WULA_DoMaintenance>执行维护</WULA_DoMaintenance>
|
||||||
|
|
||||||
|
<!-- 伤害相关翻译 -->
|
||||||
|
<WULA_DamageAffectsMaintenance>伤害会影响维护度({0}/点伤害)</WULA_DamageAffectsMaintenance>
|
||||||
|
<WULA_DamagePenalty>损伤惩罚</WULA_DamagePenalty>
|
||||||
|
<WULA_RecentDamageEvents>近期损伤事件</WULA_RecentDamageEvents>
|
||||||
|
<WULA_MaintenanceCompletedWithDamage>{0} 维护完成(修复了 {1} 损伤)</WULA_MaintenanceCompletedWithDamage>
|
||||||
|
<WULA_MaintenanceRepairedDamage>修复了 {0} 的结构损伤</WULA_MaintenanceRepairedDamage>
|
||||||
|
<WULA_DaysSinceMaintenance>距上次维护</WULA_DaysSinceMaintenance>
|
||||||
|
|
||||||
|
<!-- Global Production System -->
|
||||||
|
<WULA_GlobalBillsTab>全球生产</WULA_GlobalBillsTab>
|
||||||
|
<WULA_GlobalProduction>生产订单</WULA_GlobalProduction>
|
||||||
|
<WULA_AddProductionOrder>添加生产订单</WULA_AddProductionOrder>
|
||||||
|
<WULA_Resume>Resume</WULA_Resume>
|
||||||
|
<WULA_Pause>Pause</WULA_Pause>
|
||||||
|
<WULA_Delete>Delete</WULA_Delete>
|
||||||
|
<WULA_WaitingForResources>等待资源</WULA_WaitingForResources>
|
||||||
|
<WULA_Completed>Completed</WULA_Completed>
|
||||||
|
<WULA_Unknown>Unknown</WULA_Unknown>
|
||||||
|
<WULA_InsufficientResources>全球存储中的资源不足</WULA_InsufficientResources>
|
||||||
|
<WULA_NoAvailableRecipes>无可用配方</WULA_NoAvailableRecipes>
|
||||||
</LanguageData>
|
</LanguageData>
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Building_GlobalWorkTable.cs (修复版)
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class Building_GlobalWorkTable : Building_WorkTable
|
||||||
|
{
|
||||||
|
public GlobalProductionOrderStack globalOrderStack;
|
||||||
|
|
||||||
|
private CompPowerTrader powerComp;
|
||||||
|
private int lastProcessTick = -1;
|
||||||
|
private const int ProcessInterval = 60; // 每60tick处理一次
|
||||||
|
|
||||||
|
public Building_GlobalWorkTable()
|
||||||
|
{
|
||||||
|
globalOrderStack = new GlobalProductionOrderStack(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
Scribe_Deep.Look(ref globalOrderStack, "globalOrderStack", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||||
|
{
|
||||||
|
base.SpawnSetup(map, respawningAfterLoad);
|
||||||
|
powerComp = GetComp<CompPowerTrader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Tick()
|
||||||
|
{
|
||||||
|
base.Tick();
|
||||||
|
|
||||||
|
// 每60tick处理一次生产订单
|
||||||
|
if (Find.TickManager.TicksGame % ProcessInterval == 0 &&
|
||||||
|
Find.TickManager.TicksGame != lastProcessTick)
|
||||||
|
{
|
||||||
|
lastProcessTick = Find.TickManager.TicksGame;
|
||||||
|
|
||||||
|
if (powerComp == null || powerComp.PowerOn)
|
||||||
|
{
|
||||||
|
Log.Message($"[DEBUG] Processing orders at tick {Find.TickManager.TicksGame}");
|
||||||
|
globalOrderStack.ProcessOrders();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Message("[DEBUG] No power, skipping order processing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CurrentlyUsableForGlobalBills()
|
||||||
|
{
|
||||||
|
return (powerComp == null || powerComp.PowerOn) &&
|
||||||
|
(GetComp<CompBreakdownable>() == null || !GetComp<CompBreakdownable>().BrokenDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs
Normal file
120
Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// GlobalProductionOrder.cs (修复版)
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class GlobalProductionOrder : IExposable
|
||||||
|
{
|
||||||
|
public RecipeDef recipe;
|
||||||
|
public int targetCount = 1;
|
||||||
|
public int currentCount = 0;
|
||||||
|
public bool paused = true; // 初始状态为暂停
|
||||||
|
public float progress = 0f;
|
||||||
|
|
||||||
|
// 生产状态
|
||||||
|
public ProductionState state = ProductionState.Waiting;
|
||||||
|
|
||||||
|
public enum ProductionState
|
||||||
|
{
|
||||||
|
Waiting, // 等待资源
|
||||||
|
Producing, // 生产中
|
||||||
|
Completed // 完成
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_Defs.Look(ref recipe, "recipe");
|
||||||
|
Scribe_Values.Look(ref targetCount, "targetCount", 1);
|
||||||
|
Scribe_Values.Look(ref currentCount, "currentCount", 0);
|
||||||
|
Scribe_Values.Look(ref paused, "paused", true);
|
||||||
|
Scribe_Values.Look(ref progress, "progress", 0f);
|
||||||
|
Scribe_Values.Look(ref state, "state", ProductionState.Waiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Label => recipe.LabelCap;
|
||||||
|
public string Description => $"{currentCount}/{targetCount} {recipe.products[0].thingDef.label}";
|
||||||
|
|
||||||
|
// 检查是否有足够资源 - 修复逻辑,只检查costList
|
||||||
|
public bool HasEnoughResources()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage == null)
|
||||||
|
{
|
||||||
|
Log.Warning("GlobalStorageWorldComponent not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只检查costList,不检查ingredients
|
||||||
|
if (recipe.costList != null && recipe.costList.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var cost in recipe.costList)
|
||||||
|
{
|
||||||
|
int required = cost.count;
|
||||||
|
int available = globalStorage.GetInputStorageCount(cost.thingDef);
|
||||||
|
|
||||||
|
Log.Message($"[DEBUG] Checking {cost.thingDef.defName}: required={required}, available={available}");
|
||||||
|
|
||||||
|
if (available < required)
|
||||||
|
{
|
||||||
|
Log.Message($"[DEBUG] Insufficient {cost.thingDef.defName}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Message("[DEBUG] All resources available");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warning($"Recipe {recipe.defName} has no costList");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消耗资源 - 修复逻辑,只消耗costList
|
||||||
|
public bool ConsumeResources()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage == null) return false;
|
||||||
|
|
||||||
|
// 只消耗costList中的资源
|
||||||
|
if (recipe.costList != null)
|
||||||
|
{
|
||||||
|
foreach (var cost in recipe.costList)
|
||||||
|
{
|
||||||
|
if (!globalStorage.RemoveFromInputStorage(cost.thingDef, cost.count))
|
||||||
|
{
|
||||||
|
Log.Warning($"Failed to consume {cost.count} {cost.thingDef.defName}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.Message($"[DEBUG] Consumed {cost.count} {cost.thingDef.defName}");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生产一个产品
|
||||||
|
public void Produce()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage == null) return;
|
||||||
|
|
||||||
|
foreach (var product in recipe.products)
|
||||||
|
{
|
||||||
|
globalStorage.AddToOutputStorage(product.thingDef, product.count);
|
||||||
|
Log.Message($"[DEBUG] Produced {product.count} {product.thingDef.defName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCount++;
|
||||||
|
progress = 0f;
|
||||||
|
|
||||||
|
if (currentCount >= targetCount)
|
||||||
|
{
|
||||||
|
state = ProductionState.Completed;
|
||||||
|
Log.Message("[DEBUG] Order completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// GlobalProductionOrderStack.cs (修复版)
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class GlobalProductionOrderStack : IExposable
|
||||||
|
{
|
||||||
|
public Building_GlobalWorkTable table;
|
||||||
|
public List<GlobalProductionOrder> orders = new List<GlobalProductionOrder>();
|
||||||
|
|
||||||
|
public GlobalProductionOrderStack(Building_GlobalWorkTable table)
|
||||||
|
{
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_References.Look(ref table, "table");
|
||||||
|
Scribe_Collections.Look(ref orders, "orders", LookMode.Deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrder(GlobalProductionOrder order)
|
||||||
|
{
|
||||||
|
orders.Add(order);
|
||||||
|
|
||||||
|
// 添加到全局存储中统一管理
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null)
|
||||||
|
{
|
||||||
|
globalStorage.AddProductionOrder(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(GlobalProductionOrder order)
|
||||||
|
{
|
||||||
|
orders.Remove(order);
|
||||||
|
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null)
|
||||||
|
{
|
||||||
|
globalStorage.RemoveProductionOrder(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessOrders()
|
||||||
|
{
|
||||||
|
foreach (var order in orders)
|
||||||
|
{
|
||||||
|
if (order.paused || order.state == GlobalProductionOrder.ProductionState.Completed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 检查资源并更新状态
|
||||||
|
if (order.state == GlobalProductionOrder.ProductionState.Waiting)
|
||||||
|
{
|
||||||
|
if (order.HasEnoughResources())
|
||||||
|
{
|
||||||
|
order.state = GlobalProductionOrder.ProductionState.Producing;
|
||||||
|
Log.Message($"[DEBUG] Order {order.recipe.defName} started producing");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生产中
|
||||||
|
if (order.state == GlobalProductionOrder.ProductionState.Producing)
|
||||||
|
{
|
||||||
|
// 更清晰的进度计算
|
||||||
|
float progressPerTick = 1f / (order.recipe.workAmount * 5f); // 调整系数以控制生产速度
|
||||||
|
order.progress += progressPerTick;
|
||||||
|
|
||||||
|
if (order.progress >= 1f)
|
||||||
|
{
|
||||||
|
// 消耗资源并生产 - 在结束时扣除资源
|
||||||
|
if (order.ConsumeResources())
|
||||||
|
{
|
||||||
|
order.Produce();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 资源被其他订单消耗,回到等待状态
|
||||||
|
order.state = GlobalProductionOrder.ProductionState.Waiting;
|
||||||
|
order.progress = 0f;
|
||||||
|
Log.Message("[DEBUG] Resources consumed by another order, returning to waiting state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Message($"[DEBUG] Order {order.recipe.defName} progress: {order.progress:P0}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using LudeonTK;
|
||||||
|
using RimWorld;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class GlobalStorageWorldComponent : WorldComponent
|
||||||
|
{
|
||||||
|
public Dictionary<ThingDef, int> inputStorage = new Dictionary<ThingDef, int>();
|
||||||
|
public Dictionary<ThingDef, int> outputStorage = new Dictionary<ThingDef, int>();
|
||||||
|
|
||||||
|
// 存储生产订单
|
||||||
|
public List<GlobalProductionOrder> productionOrders = new List<GlobalProductionOrder>();
|
||||||
|
|
||||||
|
public GlobalStorageWorldComponent(World world) : base(world) { }
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
|
||||||
|
// 序列化输入存储
|
||||||
|
Scribe_Collections.Look(ref inputStorage, "inputStorage", LookMode.Def, LookMode.Value);
|
||||||
|
if (inputStorage == null) inputStorage = new Dictionary<ThingDef, int>();
|
||||||
|
|
||||||
|
// 序列化输出存储
|
||||||
|
Scribe_Collections.Look(ref outputStorage, "outputStorage", LookMode.Def, LookMode.Value);
|
||||||
|
if (outputStorage == null) outputStorage = new Dictionary<ThingDef, int>();
|
||||||
|
|
||||||
|
// 序列化生产订单
|
||||||
|
Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep);
|
||||||
|
if (productionOrders == null) productionOrders = new List<GlobalProductionOrder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入存储方法
|
||||||
|
public void AddToInputStorage(ThingDef thingDef, int count)
|
||||||
|
{
|
||||||
|
if (inputStorage.ContainsKey(thingDef))
|
||||||
|
inputStorage[thingDef] += count;
|
||||||
|
else
|
||||||
|
inputStorage[thingDef] = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RemoveFromInputStorage(ThingDef thingDef, int count)
|
||||||
|
{
|
||||||
|
if (inputStorage.ContainsKey(thingDef) && inputStorage[thingDef] >= count)
|
||||||
|
{
|
||||||
|
inputStorage[thingDef] -= count;
|
||||||
|
if (inputStorage[thingDef] <= 0)
|
||||||
|
inputStorage.Remove(thingDef);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetInputStorageCount(ThingDef thingDef)
|
||||||
|
{
|
||||||
|
return inputStorage.ContainsKey(thingDef) ? inputStorage[thingDef] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出存储方法
|
||||||
|
public void AddToOutputStorage(ThingDef thingDef, int count)
|
||||||
|
{
|
||||||
|
if (outputStorage.ContainsKey(thingDef))
|
||||||
|
outputStorage[thingDef] += count;
|
||||||
|
else
|
||||||
|
outputStorage[thingDef] = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RemoveFromOutputStorage(ThingDef thingDef, int count)
|
||||||
|
{
|
||||||
|
if (outputStorage.ContainsKey(thingDef) && outputStorage[thingDef] >= count)
|
||||||
|
{
|
||||||
|
outputStorage[thingDef] -= count;
|
||||||
|
if (outputStorage[thingDef] <= 0)
|
||||||
|
outputStorage.Remove(thingDef);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetOutputStorageCount(ThingDef thingDef)
|
||||||
|
{
|
||||||
|
return outputStorage.ContainsKey(thingDef) ? outputStorage[thingDef] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生产订单管理
|
||||||
|
public void AddProductionOrder(GlobalProductionOrder order)
|
||||||
|
{
|
||||||
|
productionOrders.Add(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveProductionOrder(GlobalProductionOrder order)
|
||||||
|
{
|
||||||
|
productionOrders.Remove(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加调试方法
|
||||||
|
[DebugAction("WULA", "Add Test Resources", actionType = DebugActionType.Action)]
|
||||||
|
public static void DebugAddTestResources()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null)
|
||||||
|
{
|
||||||
|
globalStorage.AddToInputStorage(ThingDefOf.Steel, 200);
|
||||||
|
globalStorage.AddToInputStorage(ThingDefOf.ComponentIndustrial, 100);
|
||||||
|
Log.Message("Added test resources to global storage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[DebugAction("WULA", "Spawn All Products", actionType = DebugActionType.Action)]
|
||||||
|
public static void DebugSpawnAllProducts()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null)
|
||||||
|
{
|
||||||
|
// 查找任意工作台来生成物品
|
||||||
|
var workTable = Find.CurrentMap?.listerBuildings?.allBuildingsColonist?
|
||||||
|
.FirstOrDefault(b => b is Building_GlobalWorkTable) as Building_GlobalWorkTable;
|
||||||
|
|
||||||
|
if (workTable != null && workTable.Spawned)
|
||||||
|
{
|
||||||
|
foreach (var kvp in globalStorage.outputStorage.ToList()) // 使用ToList避免修改时枚举
|
||||||
|
{
|
||||||
|
ThingDef thingDef = kvp.Key;
|
||||||
|
int count = kvp.Value;
|
||||||
|
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
int stackSize = Mathf.Min(count, thingDef.stackLimit);
|
||||||
|
Thing thing = ThingMaker.MakeThing(thingDef);
|
||||||
|
thing.stackCount = stackSize;
|
||||||
|
|
||||||
|
GenPlace.TryPlaceThing(thing, workTable.Position, workTable.Map, ThingPlaceMode.Near);
|
||||||
|
|
||||||
|
globalStorage.RemoveFromOutputStorage(thingDef, stackSize);
|
||||||
|
count -= stackSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Message("Spawned all output products");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
285
Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs
Normal file
285
Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
// ITab_GlobalBills.cs (修复版)
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using RimWorld;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
using Verse.Sound;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class ITab_GlobalBills : ITab
|
||||||
|
{
|
||||||
|
private float viewHeight = 1000f;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private GlobalProductionOrder mouseoverOrder;
|
||||||
|
|
||||||
|
private static readonly Vector2 WinSize = new Vector2(420f, 480f);
|
||||||
|
|
||||||
|
protected Building_GlobalWorkTable SelTable => (Building_GlobalWorkTable)base.SelThing;
|
||||||
|
|
||||||
|
public ITab_GlobalBills()
|
||||||
|
{
|
||||||
|
size = WinSize;
|
||||||
|
labelKey = "WULA_GlobalBillsTab";
|
||||||
|
tutorTag = "GlobalBills";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void FillTab()
|
||||||
|
{
|
||||||
|
Rect mainRect = new Rect(0f, 0f, WinSize.x, WinSize.y).ContractedBy(10f);
|
||||||
|
|
||||||
|
// 标题
|
||||||
|
Text.Font = GameFont.Medium;
|
||||||
|
Widgets.Label(new Rect(mainRect.x, mainRect.y, mainRect.width, 30f), "WULA_GlobalProduction".Translate());
|
||||||
|
Text.Font = GameFont.Small;
|
||||||
|
|
||||||
|
// 开发模式按钮区域
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
Rect devButtonRect = new Rect(mainRect.x, mainRect.y + 35f, mainRect.width, 25f);
|
||||||
|
DoDevButtons(devButtonRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单列表区域 - 调整位置
|
||||||
|
float ordersRectY = Prefs.DevMode ? mainRect.y + 65f : mainRect.y + 35f;
|
||||||
|
Rect ordersRect = new Rect(mainRect.x, ordersRectY, mainRect.width, mainRect.height - (Prefs.DevMode ? 110f : 80f));
|
||||||
|
mouseoverOrder = DoOrdersListing(ordersRect);
|
||||||
|
|
||||||
|
// 添加订单按钮
|
||||||
|
Rect addButtonRect = new Rect(mainRect.x, mainRect.yMax - 35f, mainRect.width, 30f);
|
||||||
|
if (Widgets.ButtonText(addButtonRect, "WULA_AddProductionOrder".Translate()))
|
||||||
|
{
|
||||||
|
Find.WindowStack.Add(new FloatMenu(GenerateRecipeOptions()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoDevButtons(Rect rect)
|
||||||
|
{
|
||||||
|
Rect button1Rect = new Rect(rect.x, rect.y, rect.width / 2 - 5f, rect.height);
|
||||||
|
Rect button2Rect = new Rect(rect.x + rect.width / 2 + 5f, rect.y, rect.width / 2 - 5f, rect.height);
|
||||||
|
|
||||||
|
if (Widgets.ButtonText(button1Rect, "DEV: Add Resources"))
|
||||||
|
{
|
||||||
|
AddTestResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Widgets.ButtonText(button2Rect, "DEV: Spawn Products"))
|
||||||
|
{
|
||||||
|
SpawnOutputProducts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddTestResources()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null)
|
||||||
|
{
|
||||||
|
// 添加200钢铁
|
||||||
|
ThingDef steelDef = ThingDefOf.Steel;
|
||||||
|
globalStorage.AddToInputStorage(steelDef, 200);
|
||||||
|
|
||||||
|
// 添加100零部件
|
||||||
|
ThingDef componentDef = ThingDefOf.ComponentIndustrial;
|
||||||
|
globalStorage.AddToInputStorage(componentDef, 100);
|
||||||
|
|
||||||
|
Messages.Message("Added 200 Steel and 100 Components to global storage", MessageTypeDefOf.PositiveEvent);
|
||||||
|
Log.Message("[DEBUG] Added test resources");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnOutputProducts()
|
||||||
|
{
|
||||||
|
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||||
|
if (globalStorage != null && SelTable != null && SelTable.Spawned)
|
||||||
|
{
|
||||||
|
Map map = SelTable.Map;
|
||||||
|
IntVec3 spawnCell = SelTable.Position;
|
||||||
|
int totalSpawned = 0;
|
||||||
|
|
||||||
|
// 复制列表以避免修改时枚举
|
||||||
|
var outputCopy = new Dictionary<ThingDef, int>(globalStorage.outputStorage);
|
||||||
|
|
||||||
|
foreach (var kvp in outputCopy)
|
||||||
|
{
|
||||||
|
ThingDef thingDef = kvp.Key;
|
||||||
|
int count = kvp.Value;
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
// 创建物品并放置到地图上
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
int stackSize = Mathf.Min(count, thingDef.stackLimit);
|
||||||
|
Thing thing = ThingMaker.MakeThing(thingDef);
|
||||||
|
thing.stackCount = stackSize;
|
||||||
|
|
||||||
|
if (GenPlace.TryPlaceThing(thing, spawnCell, map, ThingPlaceMode.Near))
|
||||||
|
{
|
||||||
|
globalStorage.RemoveFromOutputStorage(thingDef, stackSize);
|
||||||
|
count -= stackSize;
|
||||||
|
totalSpawned += stackSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.Message($"Spawned {totalSpawned} items at worktable location", MessageTypeDefOf.PositiveEvent);
|
||||||
|
Log.Message($"[DEBUG] Spawned {totalSpawned} output products");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GlobalProductionOrder DoOrdersListing(Rect rect)
|
||||||
|
{
|
||||||
|
GlobalProductionOrder result = null;
|
||||||
|
|
||||||
|
Widgets.DrawMenuSection(rect);
|
||||||
|
Rect outRect = rect.ContractedBy(5f);
|
||||||
|
Rect viewRect = new Rect(0f, 0f, outRect.width - 16f, viewHeight);
|
||||||
|
|
||||||
|
Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect);
|
||||||
|
|
||||||
|
float curY = 0f;
|
||||||
|
for (int i = 0; i < SelTable.globalOrderStack.orders.Count; i++)
|
||||||
|
{
|
||||||
|
var order = SelTable.globalOrderStack.orders[i];
|
||||||
|
|
||||||
|
// 增加订单行高度
|
||||||
|
Rect orderRect = new Rect(0f, curY, viewRect.width, 90f);
|
||||||
|
|
||||||
|
if (DoOrderRow(orderRect, order))
|
||||||
|
{
|
||||||
|
result = order;
|
||||||
|
}
|
||||||
|
|
||||||
|
curY += 95f; // 增加行间距
|
||||||
|
|
||||||
|
// 分隔线
|
||||||
|
if (i < SelTable.globalOrderStack.orders.Count - 1)
|
||||||
|
{
|
||||||
|
Widgets.DrawLineHorizontal(0f, curY - 2f, viewRect.width);
|
||||||
|
curY += 5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Event.current.type == EventType.Layout)
|
||||||
|
{
|
||||||
|
viewHeight = curY;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.EndScrollView();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DoOrderRow(Rect rect, GlobalProductionOrder order)
|
||||||
|
{
|
||||||
|
Widgets.DrawHighlightIfMouseover(rect);
|
||||||
|
|
||||||
|
// 增加内边距和行高
|
||||||
|
float padding = 8f;
|
||||||
|
float lineHeight = 20f;
|
||||||
|
|
||||||
|
// 订单信息
|
||||||
|
Rect infoRect = new Rect(rect.x + padding, rect.y + padding, rect.width - 100f, lineHeight);
|
||||||
|
Widgets.Label(infoRect, order.Label);
|
||||||
|
|
||||||
|
Rect descRect = new Rect(rect.x + padding, rect.y + padding + lineHeight + 2f, rect.width - 100f, lineHeight);
|
||||||
|
Widgets.Label(descRect, order.Description);
|
||||||
|
|
||||||
|
// 状态显示区域
|
||||||
|
Rect statusRect = new Rect(rect.x + padding, rect.y + padding + (lineHeight + 2f) * 2, rect.width - 100f, lineHeight);
|
||||||
|
|
||||||
|
if (order.state == GlobalProductionOrder.ProductionState.Producing)
|
||||||
|
{
|
||||||
|
// 进度条
|
||||||
|
Rect progressRect = new Rect(rect.x + padding, rect.y + padding + (lineHeight + 2f) * 2, rect.width - 100f, 18f);
|
||||||
|
Widgets.FillableBar(progressRect, order.progress);
|
||||||
|
|
||||||
|
// 进度文本
|
||||||
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
|
Widgets.Label(progressRect, $"{order.progress:P0}");
|
||||||
|
Text.Anchor = TextAnchor.UpperLeft;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string statusText = order.state switch
|
||||||
|
{
|
||||||
|
GlobalProductionOrder.ProductionState.Waiting => "WULA_WaitingForResources".Translate(),
|
||||||
|
GlobalProductionOrder.ProductionState.Completed => "WULA_Completed".Translate(),
|
||||||
|
_ => "WULA_Unknown".Translate()
|
||||||
|
};
|
||||||
|
Widgets.Label(statusRect, statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制按钮
|
||||||
|
float buttonY = rect.y + padding;
|
||||||
|
Rect pauseButtonRect = new Rect(rect.xMax - 90f, buttonY, 40f, 25f);
|
||||||
|
if (Widgets.ButtonText(pauseButtonRect, order.paused ? "WULA_Resume".Translate() : "WULA_Pause".Translate()))
|
||||||
|
{
|
||||||
|
order.paused = !order.paused;
|
||||||
|
SoundDefOf.Click.PlayOneShotOnCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect deleteButtonRect = new Rect(rect.xMax - 45f, buttonY, 40f, 25f);
|
||||||
|
if (Widgets.ButtonText(deleteButtonRect, "WULA_Delete".Translate()))
|
||||||
|
{
|
||||||
|
SelTable.globalOrderStack.Delete(order);
|
||||||
|
SoundDefOf.Click.PlayOneShotOnCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 资源检查提示 - 修复逻辑
|
||||||
|
bool shouldShowRedBorder = (order.state == GlobalProductionOrder.ProductionState.Waiting && !order.HasEnoughResources());
|
||||||
|
if (shouldShowRedBorder)
|
||||||
|
{
|
||||||
|
TooltipHandler.TipRegion(rect, "WULA_InsufficientResources".Translate());
|
||||||
|
GUI.color = Color.red;
|
||||||
|
Widgets.DrawBox(rect, 2);
|
||||||
|
GUI.color = Color.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mouse.IsOver(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FloatMenuOption> GenerateRecipeOptions()
|
||||||
|
{
|
||||||
|
var options = new List<FloatMenuOption>();
|
||||||
|
|
||||||
|
foreach (var recipe in SelTable.def.AllRecipes)
|
||||||
|
{
|
||||||
|
if (recipe.AvailableNow && recipe.AvailableOnNow(SelTable))
|
||||||
|
{
|
||||||
|
string label = recipe.LabelCap;
|
||||||
|
|
||||||
|
options.Add(new FloatMenuOption(label, () =>
|
||||||
|
{
|
||||||
|
var newOrder = new GlobalProductionOrder
|
||||||
|
{
|
||||||
|
recipe = recipe,
|
||||||
|
targetCount = 1,
|
||||||
|
paused = true // 初始暂停
|
||||||
|
};
|
||||||
|
|
||||||
|
SelTable.globalOrderStack.AddOrder(newOrder);
|
||||||
|
SoundDefOf.Click.PlayOneShotOnCamera();
|
||||||
|
Log.Message($"[DEBUG] Added order for {recipe.defName}");
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.Count == 0)
|
||||||
|
{
|
||||||
|
options.Add(new FloatMenuOption("WULA_NoAvailableRecipes".Translate(), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TabUpdate()
|
||||||
|
{
|
||||||
|
base.TabUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// HediffCompProperties_NanoRepair.cs
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using Verse;
|
using Verse;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -12,7 +13,6 @@ namespace WulaFallenEmpire
|
|||||||
public float minEnergyThreshold = 0.1f; // 最低能量阈值
|
public float minEnergyThreshold = 0.1f; // 最低能量阈值
|
||||||
public float repairCostPerHP = 0.1f; // 每点生命值修复的能量消耗
|
public float repairCostPerHP = 0.1f; // 每点生命值修复的能量消耗
|
||||||
public int repairCooldownAfterDamage = 300; // 受到伤害后的修复冷却时间
|
public int repairCooldownAfterDamage = 300; // 受到伤害后的修复冷却时间
|
||||||
public float repairTolerance = 0f; // 修复容忍度,低于此值认为已完全修复
|
|
||||||
|
|
||||||
public HediffCompProperties_NanoRepair()
|
public HediffCompProperties_NanoRepair()
|
||||||
{
|
{
|
||||||
@@ -200,7 +200,7 @@ namespace WulaFallenEmpire
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 GetPartHealth 检查是否有损伤
|
// 检查是否有损伤
|
||||||
if (HasDamagedParts())
|
if (HasDamagedParts())
|
||||||
{
|
{
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
@@ -208,14 +208,7 @@ namespace WulaFallenEmpire
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有需要治疗的疾病
|
// 不再检查疾病
|
||||||
if (Pawn.health.hediffSet.HasTendableNonInjuryNonMissingPartHediff())
|
|
||||||
{
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 检测到可治疗疾病");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] 没有检测到任何需要修复的损伤");
|
Log.Message($"[NanoRepair] 没有检测到任何需要修复的损伤");
|
||||||
return false;
|
return false;
|
||||||
@@ -235,12 +228,12 @@ namespace WulaFallenEmpire
|
|||||||
float maxHealth = part.def.GetMaxHealth(Pawn);
|
float maxHealth = part.def.GetMaxHealth(Pawn);
|
||||||
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
||||||
|
|
||||||
// 使用修复容忍度,只有当损伤大于容忍度时才认为需要修复
|
// 不再使用修复容忍度,任何损伤都需要修复
|
||||||
if (currentHealth < maxHealth - Props.repairTolerance)
|
if (currentHealth < maxHealth)
|
||||||
{
|
{
|
||||||
damagedCount++;
|
damagedCount++;
|
||||||
if (debugCounter % 10 == 0 && damagedCount == 1)
|
if (debugCounter % 10 == 0 && damagedCount == 1)
|
||||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 有损伤: {currentHealth}/{maxHealth} (容忍度: {Props.repairTolerance})");
|
Log.Message($"[NanoRepair] 部位 {part.def.defName} 有损伤: {currentHealth}/{maxHealth}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,8 +257,8 @@ namespace WulaFallenEmpire
|
|||||||
float maxHealth = part.def.GetMaxHealth(Pawn);
|
float maxHealth = part.def.GetMaxHealth(Pawn);
|
||||||
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
||||||
|
|
||||||
// 使用修复容忍度
|
// 不再使用修复容忍度,任何损伤都需要修复
|
||||||
if (currentHealth < maxHealth - Props.repairTolerance)
|
if (currentHealth < maxHealth)
|
||||||
{
|
{
|
||||||
damagedParts.Add(part);
|
damagedParts.Add(part);
|
||||||
if (debugCounter % 10 == 0 && damagedParts.Count <= 3)
|
if (debugCounter % 10 == 0 && damagedParts.Count <= 3)
|
||||||
@@ -309,13 +302,7 @@ namespace WulaFallenEmpire
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 最后修复疾病
|
// 不再修复疾病
|
||||||
if (TryRepairDiseases(energyNeed))
|
|
||||||
{
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 已修复疾病");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] 没有执行任何修复");
|
Log.Message($"[NanoRepair] 没有执行任何修复");
|
||||||
@@ -450,110 +437,18 @@ namespace WulaFallenEmpire
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryRepairDiseases(Need energyNeed)
|
// 新的修复逻辑:完美修复所有伤口
|
||||||
{
|
|
||||||
var diseases = Pawn.health.hediffSet.GetTendableNonInjuryNonMissingPartHediffs();
|
|
||||||
if (diseases == null)
|
|
||||||
{
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 没有可治疗疾病");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int diseaseCount = 0;
|
|
||||||
foreach (var disease in diseases)
|
|
||||||
{
|
|
||||||
if (disease.TendableNow())
|
|
||||||
diseaseCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diseaseCount == 0)
|
|
||||||
{
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 没有可治疗的疾病");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 检查修复疾病,共有 {diseaseCount} 个");
|
|
||||||
|
|
||||||
foreach (var disease in diseases)
|
|
||||||
{
|
|
||||||
if (disease.TendableNow())
|
|
||||||
{
|
|
||||||
float repairCost = CalculateRepairCost(disease);
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 尝试修复疾病 {disease.def.defName}, 严重性: {disease.Severity:F2}, 成本: {repairCost:F2}, 当前能量: {energyNeed.CurLevel:F2}");
|
|
||||||
|
|
||||||
if (energyNeed.CurLevel >= repairCost)
|
|
||||||
{
|
|
||||||
if (RepairDisease(disease, repairCost))
|
|
||||||
{
|
|
||||||
energyNeed.CurLevel -= repairCost;
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 成功修复疾病 {disease.def.defName}, 消耗能量: {repairCost:F2}");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 能量不足修复疾病: {energyNeed.CurLevel:F2} < {repairCost:F2}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float CalculateRepairCost(Hediff hediff)
|
|
||||||
{
|
|
||||||
float baseCost = Props.repairCostPerHP;
|
|
||||||
|
|
||||||
// 根据机械族的能量消耗属性调整成本
|
|
||||||
var mechEnergyLoss = Pawn.GetStatValue(StatDefOf.MechEnergyLossPerHP);
|
|
||||||
if (mechEnergyLoss > 0)
|
|
||||||
{
|
|
||||||
baseCost *= mechEnergyLoss;
|
|
||||||
}
|
|
||||||
|
|
||||||
float severityMultiplier = 1.0f;
|
|
||||||
|
|
||||||
if (hediff is Hediff_Injury injury)
|
|
||||||
{
|
|
||||||
severityMultiplier = injury.Severity;
|
|
||||||
}
|
|
||||||
else if (hediff is Hediff_MissingPart)
|
|
||||||
{
|
|
||||||
// 缺失部件修复成本使用正常计算
|
|
||||||
severityMultiplier = 1.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
severityMultiplier = hediff.Severity * 1.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float finalCost = baseCost * severityMultiplier;
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 计算修复成本: 基础={Props.repairCostPerHP}, 机械族能耗系数={mechEnergyLoss}, 严重性系数={severityMultiplier}, 最终成本={finalCost:F2}");
|
|
||||||
|
|
||||||
return finalCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool RepairDamagedPart(BodyPartRecord part, float repairCost)
|
private bool RepairDamagedPart(BodyPartRecord part, float repairCost)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
float maxHealth = part.def.GetMaxHealth(Pawn);
|
float maxHealth = part.def.GetMaxHealth(Pawn);
|
||||||
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
||||||
float healthToRepair = Mathf.Min(maxHealth - currentHealth, repairCost / Props.repairCostPerHP);
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] 开始修复部位 {part.def.defName}, 计划修复量: {healthToRepair:F1}");
|
Log.Message($"[NanoRepair] 开始修复部位 {part.def.defName}, 当前健康: {currentHealth:F1}/{maxHealth:F1}");
|
||||||
|
|
||||||
// 直接修复部位的健康值,而不是查找特定的hediff
|
// 获取该部位的所有hediff
|
||||||
// 找到该部位的所有hediff并尝试修复
|
|
||||||
var hediffsOnPart = new List<Hediff>();
|
var hediffsOnPart = new List<Hediff>();
|
||||||
foreach (var hediff in Pawn.health.hediffSet.hediffs)
|
foreach (var hediff in Pawn.health.hediffSet.hediffs)
|
||||||
{
|
{
|
||||||
@@ -575,17 +470,10 @@ namespace WulaFallenEmpire
|
|||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] 在部位 {part.def.defName} 上找到 {hediffsOnPart.Count} 个hediff");
|
Log.Message($"[NanoRepair] 在部位 {part.def.defName} 上找到 {hediffsOnPart.Count} 个hediff");
|
||||||
|
|
||||||
// 按严重性排序,先修复最严重的hediff
|
|
||||||
hediffsOnPart.Sort((a, b) => b.Severity.CompareTo(a.Severity));
|
|
||||||
|
|
||||||
float remainingRepair = healthToRepair;
|
|
||||||
bool anyRepairDone = false;
|
bool anyRepairDone = false;
|
||||||
|
|
||||||
foreach (var hediff in hediffsOnPart)
|
foreach (var hediff in hediffsOnPart)
|
||||||
{
|
{
|
||||||
if (remainingRepair <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// 检查hediff是否可修复
|
// 检查hediff是否可修复
|
||||||
if (!CanRepairHediff(hediff))
|
if (!CanRepairHediff(hediff))
|
||||||
{
|
{
|
||||||
@@ -594,25 +482,28 @@ namespace WulaFallenEmpire
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float healAmount = Mathf.Min(hediff.Severity, remainingRepair);
|
// 新的修复逻辑:对于小于1的伤口,直接删除
|
||||||
hediff.Severity -= healAmount;
|
if (hediff.Severity < 1.0f)
|
||||||
remainingRepair -= healAmount;
|
|
||||||
anyRepairDone = true;
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 修复hediff {hediff.def.defName}, 修复量: {healAmount:F1}, 剩余严重性: {hediff.Severity:F1}");
|
|
||||||
|
|
||||||
// 使用修复容忍度,只有当严重性大于容忍度时才移除hediff
|
|
||||||
if (hediff.Severity <= Props.repairTolerance)
|
|
||||||
{
|
{
|
||||||
Pawn.health.RemoveHediff(hediff);
|
Pawn.health.RemoveHediff(hediff);
|
||||||
|
anyRepairDone = true;
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] hediff {hediff.def.defName} 已完全修复并移除");
|
Log.Message($"[NanoRepair] 删除严重性小于1的hediff: {hediff.def.defName} (严重性: {hediff.Severity:F2})");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 对于大于等于1的伤口,完全修复
|
||||||
|
float originalSeverity = hediff.Severity;
|
||||||
|
hediff.Severity = 0f;
|
||||||
|
Pawn.health.RemoveHediff(hediff);
|
||||||
|
anyRepairDone = true;
|
||||||
|
if (debugCounter % 10 == 0)
|
||||||
|
Log.Message($"[NanoRepair] 完全修复hediff: {hediff.def.defName} (严重性: {originalSeverity:F2} -> 0)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
if (debugCounter % 10 == 0)
|
||||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 修复完成,总修复量: {healthToRepair - remainingRepair:F1}");
|
Log.Message($"[NanoRepair] 部位 {part.def.defName} 修复完成,执行了 {anyRepairDone} 次修复");
|
||||||
|
|
||||||
return anyRepairDone;
|
return anyRepairDone;
|
||||||
}
|
}
|
||||||
@@ -626,12 +517,16 @@ namespace WulaFallenEmpire
|
|||||||
// 检查hediff是否可修复
|
// 检查hediff是否可修复
|
||||||
private bool CanRepairHediff(Hediff hediff)
|
private bool CanRepairHediff(Hediff hediff)
|
||||||
{
|
{
|
||||||
// 如果是机械族特有的hediff,总是可以修复
|
// 跳过疾病
|
||||||
if (IsMechSpecificHediff(hediff))
|
if (IsDisease(hediff))
|
||||||
return true;
|
{
|
||||||
|
if (debugCounter % 10 == 0)
|
||||||
|
Log.Message($"[NanoRepair] 跳过疾病: {hediff.def.defName}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是可治疗的hediff,可以修复
|
// 如果是机械族特有的hediff,可以修复
|
||||||
if (hediff.TendableNow())
|
if (IsMechSpecificHediff(hediff))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// 如果是损伤类型的hediff,可以修复
|
// 如果是损伤类型的hediff,可以修复
|
||||||
@@ -642,6 +537,26 @@ namespace WulaFallenEmpire
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否是疾病
|
||||||
|
private bool IsDisease(Hediff hediff)
|
||||||
|
{
|
||||||
|
// 这里可以定义哪些hediff被认为是疾病
|
||||||
|
// 常见的疾病类型
|
||||||
|
string[] diseaseKeywords = {
|
||||||
|
"Disease", "Flu", "Plague", "Infection", "Malaria",
|
||||||
|
"SleepingSickness", "FibrousMechanites", "SensoryMechanites",
|
||||||
|
"WoundInfection", "FoodPoisoning", "GutWorms", "MuscleParasites"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string keyword in diseaseKeywords)
|
||||||
|
{
|
||||||
|
if (hediff.def.defName.Contains(keyword))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 将缺失部件转换为指定的hediff
|
// 将缺失部件转换为指定的hediff
|
||||||
private bool ConvertMissingPartToInjury(Hediff_MissingPart missingPart, float repairCost)
|
private bool ConvertMissingPartToInjury(Hediff_MissingPart missingPart, float repairCost)
|
||||||
{
|
{
|
||||||
@@ -701,33 +616,6 @@ namespace WulaFallenEmpire
|
|||||||
hediff.def.defName.Contains("Gunshot"); // 包括枪伤
|
hediff.def.defName.Contains("Gunshot"); // 包括枪伤
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool RepairDisease(Hediff disease, float repairCost)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 修复疾病
|
|
||||||
float healAmount = Mathf.Min(disease.Severity, repairCost / (Props.repairCostPerHP * 1.5f));
|
|
||||||
disease.Severity -= healAmount;
|
|
||||||
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 修复疾病 {disease.def.defName}, 修复量: {healAmount:F2}, 剩余严重性: {disease.Severity:F2}");
|
|
||||||
|
|
||||||
// 使用修复容忍度
|
|
||||||
if (disease.Severity <= Props.repairTolerance)
|
|
||||||
{
|
|
||||||
Pawn.health.RemoveHediff(disease);
|
|
||||||
if (debugCounter % 10 == 0)
|
|
||||||
Log.Message($"[NanoRepair] 疾病 {disease.def.defName} 已完全修复并移除");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error($"[NanoRepair] 修复疾病 {disease.def.defName} 时出错: {ex}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||||
{
|
{
|
||||||
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
|
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
|
||||||
|
|||||||
@@ -1,35 +1,32 @@
|
|||||||
|
// Building_MaintenancePod.cs
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using Verse;
|
using Verse;
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
namespace WulaFallenEmpire
|
||||||
{
|
{
|
||||||
public class CompProperties_MaintenanceCycle : CompProperties_BiosculpterPod_BaseCycle
|
public class Building_MaintenancePod : Building
|
||||||
{
|
{
|
||||||
public HediffDef hediffToRemove;
|
public CompMaintenancePod MaintenanceComp => GetComp<CompMaintenancePod>();
|
||||||
|
|
||||||
public CompProperties_MaintenanceCycle()
|
protected override void Tick()
|
||||||
{
|
{
|
||||||
compClass = typeof(CompMaintenanceCycle);
|
base.Tick();
|
||||||
|
// 建筑级别的特殊逻辑可以在这里添加
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class CompMaintenanceCycle : CompBiosculpterPod_Cycle
|
public override string GetInspectString()
|
||||||
{
|
|
||||||
public new CompProperties_MaintenanceCycle Props => (CompProperties_MaintenanceCycle)props;
|
|
||||||
|
|
||||||
public override void CycleCompleted(Pawn pawn)
|
|
||||||
{
|
{
|
||||||
if (pawn == null)
|
string baseString = base.GetInspectString();
|
||||||
|
string maintenanceString = MaintenanceComp?.CompInspectStringExtra();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(maintenanceString))
|
||||||
{
|
{
|
||||||
return;
|
if (!string.IsNullOrEmpty(baseString))
|
||||||
|
return baseString + "\n" + maintenanceString;
|
||||||
|
return maintenanceString;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
|
return baseString;
|
||||||
if (hediff != null)
|
|
||||||
{
|
|
||||||
hediff.Severity = 0f;
|
|
||||||
Messages.Message("WULA_MaintenanceCycleComplete".Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.PositiveEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,16 +15,25 @@ namespace WulaFallenEmpire
|
|||||||
public SoundDef enterSound;
|
public SoundDef enterSound;
|
||||||
public SoundDef exitSound;
|
public SoundDef exitSound;
|
||||||
public EffecterDef operatingEffecter;
|
public EffecterDef operatingEffecter;
|
||||||
public int baseDurationTicks = 60000;
|
|
||||||
public float ticksPerSeverity = 0f;
|
// 时间相关
|
||||||
|
public int baseDurationTicks = 60000; // 基础维护时间(1天)
|
||||||
|
public float ticksPerNeedLevel = 120000f; // 每点需求降低需要的时间
|
||||||
|
|
||||||
|
// 电力消耗
|
||||||
public float powerConsumptionRunning = 250f;
|
public float powerConsumptionRunning = 250f;
|
||||||
public float powerConsumptionIdle = 50f;
|
public float powerConsumptionIdle = 50f;
|
||||||
public HediffDef hediffToRemove;
|
|
||||||
public float componentCostPerSeverity = 1f;
|
|
||||||
public int baseComponentCost = 0;
|
|
||||||
public float minSeverityToMaintain = 0.75f;
|
|
||||||
public float hediffSeverityAfterCycle = 0.01f;
|
|
||||||
|
|
||||||
|
// 组件消耗
|
||||||
|
public float componentCostPerNeedLevel = 2f;
|
||||||
|
public int baseComponentCost = 1;
|
||||||
|
|
||||||
|
// 维护效果
|
||||||
|
public float minNeedLevelToMaintain = 0.3f; // 低于此值才需要维护
|
||||||
|
public float needLevelAfterCycle = 1.0f; // 维护后的需求水平
|
||||||
|
public bool healInjuries = true; // 是否治疗损伤
|
||||||
|
public bool healMissingParts = true; // 是否修复缺失部位
|
||||||
|
public int maxInjuriesHealedPerCycle = 5; // 每次维护最多治疗的损伤数量
|
||||||
public CompProperties_MaintenancePod()
|
public CompProperties_MaintenancePod()
|
||||||
{
|
{
|
||||||
compClass = typeof(CompMaintenancePod);
|
compClass = typeof(CompMaintenancePod);
|
||||||
@@ -40,45 +49,55 @@ namespace WulaFallenEmpire
|
|||||||
private CompRefuelable refuelableComp;
|
private CompRefuelable refuelableComp;
|
||||||
private int ticksRemaining;
|
private int ticksRemaining;
|
||||||
private MaintenancePodState state = MaintenancePodState.Idle;
|
private MaintenancePodState state = MaintenancePodState.Idle;
|
||||||
|
private Effecter operatingEffecter;
|
||||||
private static readonly Texture2D CancelIcon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel");
|
private static readonly Texture2D CancelIcon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel");
|
||||||
private static readonly Texture2D EnterIcon = ContentFinder<Texture2D>.Get("UI/Commands/PodEject");
|
private static readonly Texture2D EnterIcon = ContentFinder<Texture2D>.Get("UI/Commands/PodEject");
|
||||||
|
|
||||||
// ===================== Properties =====================
|
// ===================== Properties =====================
|
||||||
public CompProperties_MaintenancePod Props => (CompProperties_MaintenancePod)props;
|
public CompProperties_MaintenancePod Props => (CompProperties_MaintenancePod)props;
|
||||||
public MaintenancePodState State => state;
|
public MaintenancePodState State => state;
|
||||||
public Pawn Occupant => innerContainer.FirstOrDefault() as Pawn;
|
public Pawn Occupant => innerContainer.FirstOrDefault() as Pawn;
|
||||||
public bool PowerOn => powerComp != null && powerComp.PowerOn;
|
public bool PowerOn => powerComp != null && powerComp.PowerOn;
|
||||||
|
public float RequiredComponents
|
||||||
public float RequiredComponents(Pawn pawn)
|
|
||||||
{
|
{
|
||||||
if (pawn == null || Props.hediffToRemove == null) return Props.baseComponentCost;
|
get
|
||||||
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
|
{
|
||||||
if (hediff == null) return Props.baseComponentCost;
|
var occupant = Occupant;
|
||||||
return Props.baseComponentCost + (int)(hediff.Severity * Props.componentCostPerSeverity);
|
if (occupant == null) return Props.baseComponentCost;
|
||||||
}
|
|
||||||
|
|
||||||
public int RequiredDuration(Pawn pawn)
|
var maintenanceNeed = occupant.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
if (maintenanceNeed == null) return Props.baseComponentCost;
|
||||||
|
|
||||||
|
// 计算基于当前需求水平的组件需求
|
||||||
|
float needDeficit = 1.0f - maintenanceNeed.CurLevel;
|
||||||
|
return Props.baseComponentCost + (needDeficit * Props.componentCostPerNeedLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int RequiredDuration
|
||||||
{
|
{
|
||||||
if (pawn == null || Props.hediffToRemove == null) return Props.baseDurationTicks;
|
get
|
||||||
Hediff hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
|
{
|
||||||
if (hediff == null) return Props.baseDurationTicks;
|
var occupant = Occupant;
|
||||||
return Props.baseDurationTicks + (int)(hediff.Severity * Props.ticksPerSeverity);
|
if (occupant == null) return Props.baseDurationTicks;
|
||||||
}
|
|
||||||
|
|
||||||
|
var maintenanceNeed = occupant.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
if (maintenanceNeed == null) return Props.baseDurationTicks;
|
||||||
|
|
||||||
|
// 计算基于当前需求水平的维护时间
|
||||||
|
float needDeficit = 1.0f - maintenanceNeed.CurLevel;
|
||||||
|
return Props.baseDurationTicks + (int)(needDeficit * Props.ticksPerNeedLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
// ===================== Setup =====================
|
// ===================== Setup =====================
|
||||||
public CompMaintenancePod()
|
public CompMaintenancePod()
|
||||||
{
|
{
|
||||||
innerContainer = new ThingOwner<Thing>(this, false, LookMode.Deep);
|
innerContainer = new ThingOwner<Thing>(this, false, LookMode.Deep);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||||
{
|
{
|
||||||
base.PostSpawnSetup(respawningAfterLoad);
|
base.PostSpawnSetup(respawningAfterLoad);
|
||||||
powerComp = parent.TryGetComp<CompPowerTrader>();
|
powerComp = parent.TryGetComp<CompPowerTrader>();
|
||||||
refuelableComp = parent.TryGetComp<CompRefuelable>();
|
refuelableComp = parent.TryGetComp<CompRefuelable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostExposeData()
|
public override void PostExposeData()
|
||||||
{
|
{
|
||||||
base.PostExposeData();
|
base.PostExposeData();
|
||||||
@@ -86,361 +105,335 @@ namespace WulaFallenEmpire
|
|||||||
Scribe_Values.Look(ref ticksRemaining, "ticksRemaining", 0);
|
Scribe_Values.Look(ref ticksRemaining, "ticksRemaining", 0);
|
||||||
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
|
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostDestroy(DestroyMode mode, Map previousMap)
|
public override void PostDestroy(DestroyMode mode, Map previousMap)
|
||||||
{
|
{
|
||||||
base.PostDestroy(mode, previousMap);
|
base.PostDestroy(mode, previousMap);
|
||||||
// If the pod is deconstructed or destroyed, eject the occupant to prevent deletion.
|
|
||||||
if (mode == DestroyMode.Deconstruct || mode == DestroyMode.KillFinalize)
|
if (mode == DestroyMode.Deconstruct || mode == DestroyMode.KillFinalize)
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] Pod destroyed (mode: {mode}). Ejecting pawn.");
|
|
||||||
EjectPawn();
|
EjectPawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===================== IThingHolder Implementation =====================
|
// ===================== IThingHolder Implementation =====================
|
||||||
public void GetChildHolders(List<IThingHolder> outChildren)
|
public void GetChildHolders(List<IThingHolder> outChildren)
|
||||||
{
|
{
|
||||||
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
|
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThingOwner GetDirectlyHeldThings()
|
public ThingOwner GetDirectlyHeldThings()
|
||||||
{
|
{
|
||||||
return innerContainer;
|
return innerContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===================== Core Logic =====================
|
// ===================== Core Logic =====================
|
||||||
public override void CompTick()
|
public override void CompTick()
|
||||||
{
|
{
|
||||||
base.CompTick();
|
base.CompTick();
|
||||||
if (!parent.Spawned) return;
|
if (!parent.Spawned) return;
|
||||||
|
// 更新电力消耗
|
||||||
if (state == MaintenancePodState.Running)
|
|
||||||
{
|
|
||||||
if (PowerOn)
|
|
||||||
{
|
|
||||||
ticksRemaining--;
|
|
||||||
if (ticksRemaining <= 0)
|
|
||||||
{
|
|
||||||
CycleFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (powerComp != null)
|
if (powerComp != null)
|
||||||
{
|
{
|
||||||
powerComp.PowerOutput = -(state == MaintenancePodState.Running ? Props.powerConsumptionRunning : Props.powerConsumptionIdle);
|
powerComp.PowerOutput = -(state == MaintenancePodState.Running ? Props.powerConsumptionRunning : Props.powerConsumptionIdle);
|
||||||
}
|
}
|
||||||
}
|
// 运行维护周期
|
||||||
|
if (state == MaintenancePodState.Running && PowerOn)
|
||||||
|
{
|
||||||
|
ticksRemaining--;
|
||||||
|
|
||||||
|
// 更新效果器
|
||||||
|
if (Props.operatingEffecter != null)
|
||||||
|
{
|
||||||
|
if (operatingEffecter == null)
|
||||||
|
{
|
||||||
|
operatingEffecter = Props.operatingEffecter.Spawn();
|
||||||
|
}
|
||||||
|
operatingEffecter.EffectTick(parent, Occupant);
|
||||||
|
}
|
||||||
|
if (ticksRemaining <= 0)
|
||||||
|
{
|
||||||
|
CycleFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (operatingEffecter != null)
|
||||||
|
{
|
||||||
|
operatingEffecter.Cleanup();
|
||||||
|
operatingEffecter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
public void StartCycle(Pawn pawn)
|
public void StartCycle(Pawn pawn)
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] StartCycle called for pawn: {pawn.LabelShortCap}");
|
if (pawn == null) return;
|
||||||
float required = RequiredComponents(pawn);
|
// 检查组件是否足够
|
||||||
if (refuelableComp.Fuel < required)
|
float requiredComponents = RequiredComponents;
|
||||||
|
if (refuelableComp.Fuel < requiredComponents)
|
||||||
{
|
{
|
||||||
Log.Error($"[WulaPodDebug] ERROR: Tried to start cycle for {pawn.LabelShort} without enough components.");
|
Messages.Message("WULA_MaintenancePod_NotEnoughComponents".Translate(requiredComponents.ToString("F0")), MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 消耗组件
|
||||||
if (required > 0)
|
if (requiredComponents > 0)
|
||||||
{
|
{
|
||||||
refuelableComp.ConsumeFuel(required);
|
refuelableComp.ConsumeFuel(requiredComponents);
|
||||||
}
|
}
|
||||||
|
// 将 pawn 放入容器
|
||||||
Log.Warning($"[WulaPodDebug] Pawn state before action: holdingOwner is {(pawn.holdingOwner == null ? "NULL" : "NOT NULL")}, Spawned is {pawn.Spawned}");
|
|
||||||
|
|
||||||
// THE ACTUAL FIX: A pawn, whether held or not, must be despawned before being put in a container.
|
|
||||||
if (pawn.Spawned)
|
if (pawn.Spawned)
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] Pawn is spawned. Despawning...");
|
|
||||||
pawn.DeSpawn(DestroyMode.Vanish);
|
pawn.DeSpawn(DestroyMode.Vanish);
|
||||||
}
|
}
|
||||||
Log.Warning($"[WulaPodDebug] Attempting to add/transfer pawn to container.");
|
|
||||||
innerContainer.TryAddOrTransfer(pawn);
|
innerContainer.TryAddOrTransfer(pawn);
|
||||||
|
// 开始维护周期
|
||||||
|
|
||||||
state = MaintenancePodState.Running;
|
state = MaintenancePodState.Running;
|
||||||
ticksRemaining = RequiredDuration(pawn);
|
ticksRemaining = RequiredDuration;
|
||||||
Log.Warning($"[WulaPodDebug] Cycle started. Ticks remaining: {ticksRemaining}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 播放进入音效
|
||||||
|
if (Props.enterSound != null)
|
||||||
|
{
|
||||||
|
Props.enterSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
|
||||||
|
}
|
||||||
|
Messages.Message("WULA_MaintenanceCycleStarted".Translate(pawn.LabelShortCap), MessageTypeDefOf.PositiveEvent);
|
||||||
|
}
|
||||||
private void CycleFinished()
|
private void CycleFinished()
|
||||||
{
|
{
|
||||||
Pawn occupant = Occupant;
|
var occupant = Occupant;
|
||||||
Log.Warning($"[WulaPodDebug] CycleFinished. Occupant: {(occupant == null ? "NULL" : occupant.LabelShortCap)}");
|
|
||||||
if (occupant == null)
|
if (occupant == null)
|
||||||
{
|
{
|
||||||
Log.Error("[WulaPodDebug] ERROR: Maintenance cycle finished, but no one was inside.");
|
|
||||||
state = MaintenancePodState.Idle;
|
state = MaintenancePodState.Idle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 执行维护效果
|
||||||
|
PerformMaintenanceEffects(occupant);
|
||||||
|
|
||||||
// 1. Fix the maintenance hediff
|
// 弹出 pawn
|
||||||
bool maintenanceDone = false;
|
EjectPawn();
|
||||||
if (Props.hediffToRemove != null)
|
|
||||||
|
Messages.Message("WULA_MaintenanceCycleComplete".Translate(occupant.LabelShortCap), MessageTypeDefOf.PositiveEvent);
|
||||||
|
}
|
||||||
|
private void PerformMaintenanceEffects(Pawn pawn)
|
||||||
|
{
|
||||||
|
var maintenanceNeed = pawn.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
|
||||||
|
// 1. 恢复维护需求
|
||||||
|
if (maintenanceNeed != null)
|
||||||
{
|
{
|
||||||
Hediff hediff = occupant.health.hediffSet.GetFirstHediffOfDef(Props.hediffToRemove);
|
maintenanceNeed.PerformMaintenance(Props.needLevelAfterCycle);
|
||||||
if (hediff != null)
|
|
||||||
{
|
|
||||||
hediff.Severity = Props.hediffSeverityAfterCycle;
|
|
||||||
Messages.Message("WULA_MaintenanceComplete".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.PositiveEvent);
|
|
||||||
maintenanceDone = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// 2. 治疗损伤(如果启用)
|
||||||
// 2. Heal all other injuries and missing parts
|
if (Props.healInjuries)
|
||||||
|
{
|
||||||
|
HealInjuries(pawn);
|
||||||
|
}
|
||||||
|
// 3. 修复缺失部位(如果启用)
|
||||||
|
if (Props.healMissingParts)
|
||||||
|
{
|
||||||
|
HealMissingParts(pawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void HealInjuries(Pawn pawn)
|
||||||
|
{
|
||||||
int injuriesHealed = 0;
|
int injuriesHealed = 0;
|
||||||
// Loop until no more health conditions can be fixed
|
var injuries = pawn.health.hediffSet.hediffs
|
||||||
while (HealthUtility.TryGetWorstHealthCondition(occupant, out var hediffToFix, out var _))
|
.Where(h => h.def.isBad && h.Visible && h.def != HediffDefOf.BloodLoss)
|
||||||
|
.ToList();
|
||||||
|
foreach (var injury in injuries)
|
||||||
{
|
{
|
||||||
// Ensure we don't try to "heal" the maintenance hediff itself, as it's handled separately.
|
if (injuriesHealed >= Props.maxInjuriesHealedPerCycle)
|
||||||
if (hediffToFix != null && hediffToFix.def == Props.hediffToRemove)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
pawn.health.RemoveHediff(injury);
|
||||||
|
injuriesHealed++;
|
||||||
// Store the state before attempting to fix
|
|
||||||
int initialHediffCount = occupant.health.hediffSet.hediffs.Count;
|
|
||||||
var hediffsBefore = new HashSet<Hediff>(occupant.health.hediffSet.hediffs);
|
|
||||||
|
|
||||||
// Attempt to fix the worst condition
|
|
||||||
HealthUtility.FixWorstHealthCondition(occupant);
|
|
||||||
|
|
||||||
// Check if a change actually occurred
|
|
||||||
bool conditionFixed = initialHediffCount > occupant.health.hediffSet.hediffs.Count ||
|
|
||||||
!hediffsBefore.SetEquals(occupant.health.hediffSet.hediffs);
|
|
||||||
|
|
||||||
if (conditionFixed)
|
|
||||||
{
|
|
||||||
injuriesHealed++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If FixWorstHealthCondition did nothing, it means it can't handle
|
|
||||||
// the current worst condition. We must break to avoid an infinite loop.
|
|
||||||
Log.Warning($"[WulaPodDebug] Halting healing loop. FixWorstHealthCondition did not resolve: {hediffToFix?.LabelCap ?? "a missing part"}.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (injuriesHealed > 0)
|
if (injuriesHealed > 0)
|
||||||
{
|
{
|
||||||
Messages.Message("WULA_MaintenanceHealedAllWounds".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.PositiveEvent);
|
Messages.Message("WULA_MaintenanceHealedInjuries".Translate(pawn.LabelShortCap, injuriesHealed), MessageTypeDefOf.PositiveEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void HealMissingParts(Pawn pawn)
|
||||||
|
{
|
||||||
|
var missingParts = pawn.health.hediffSet.GetMissingPartsCommonAncestors();
|
||||||
|
int partsHealed = 0;
|
||||||
|
foreach (var missingPart in missingParts)
|
||||||
|
{
|
||||||
|
if (partsHealed >= 1) // 每次最多修复一个缺失部位
|
||||||
|
break;
|
||||||
|
pawn.health.RemoveHediff(missingPart);
|
||||||
|
partsHealed++;
|
||||||
|
}
|
||||||
|
if (partsHealed > 0)
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_MaintenanceHealedParts".Translate(pawn.LabelShortCap), MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
else if (!maintenanceDone)
|
|
||||||
{
|
|
||||||
// If nothing was done at all, give a neutral message
|
|
||||||
Messages.Message("WULA_MaintenanceNoEffect".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.NeutralEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
EjectPawn();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EjectPawn(bool interrupted = false)
|
public void EjectPawn(bool interrupted = false)
|
||||||
{
|
{
|
||||||
Pawn occupant = Occupant;
|
var occupant = Occupant;
|
||||||
Log.Warning($"[WulaPodDebug] EjectPawn. Occupant: {(occupant == null ? "NULL" : occupant.LabelShortCap)}");
|
|
||||||
if (occupant != null)
|
if (occupant != null)
|
||||||
{
|
{
|
||||||
Map mapToUse = parent.Map ?? Find.CurrentMap;
|
// 弹出到交互单元格
|
||||||
if (mapToUse == null)
|
innerContainer.TryDropAll(parent.InteractionCell, parent.Map, ThingPlaceMode.Near);
|
||||||
{
|
|
||||||
// Try to find the map from nearby things
|
|
||||||
mapToUse = GenClosest.ClosestThing_Global(occupant.Position, Gen.YieldSingle(parent), 99999f, (thing) => thing.Map != null)?.Map;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapToUse != null)
|
// 播放退出音效
|
||||||
|
if (Props.exitSound != null)
|
||||||
{
|
{
|
||||||
innerContainer.TryDropAll(parent.InteractionCell, mapToUse, ThingPlaceMode.Near);
|
Props.exitSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
|
||||||
if (Props.exitSound != null)
|
|
||||||
{
|
|
||||||
SoundStarter.PlayOneShot(Props.exitSound, new TargetInfo(parent.Position, mapToUse));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
// 如果被中断,应用负面效果
|
||||||
{
|
|
||||||
Log.Error($"[WulaPodDebug] EjectPawn FAILED: No valid map found to eject {occupant.LabelShortCap}. The pawn will be lost.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional logic to handle occupant if needed
|
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
occupant.needs?.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.SoakingWet);
|
occupant.needs?.mood?.thoughts?.memories?.TryGainMemory(ThoughtDefOf.SoakingWet);
|
||||||
occupant.health?.AddHediff(HediffDefOf.BiosculptingSickness);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
innerContainer.Clear();
|
innerContainer.Clear();
|
||||||
state = MaintenancePodState.Idle;
|
state = MaintenancePodState.Idle;
|
||||||
Log.Warning($"[WulaPodDebug] EjectPawn finished. State set to Idle.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 清理效果器
|
||||||
|
if (operatingEffecter != null)
|
||||||
|
{
|
||||||
|
operatingEffecter.Cleanup();
|
||||||
|
operatingEffecter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
// ===================== UI & Gizmos =====================
|
// ===================== UI & Gizmos =====================
|
||||||
public override string CompInspectStringExtra()
|
public override string CompInspectStringExtra()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.AppendLine("WULA_MaintenancePod_Status".Translate() + ": " + $"WULA_MaintenancePod_State_{state}".Translate());
|
sb.AppendLine("WULA_MaintenancePod_Status".Translate() + ": " + $"WULA_MaintenancePod_State_{state}".Translate());
|
||||||
|
if (state == MaintenancePodState.Running && Occupant != null)
|
||||||
if (state == MaintenancePodState.Running)
|
|
||||||
{
|
{
|
||||||
if (Occupant != null)
|
sb.AppendLine("Contains".Translate() + ": " + Occupant.NameShortColored.Resolve());
|
||||||
{
|
|
||||||
sb.AppendLine("Contains".Translate() + ": " + Occupant.NameShortColored.Resolve());
|
|
||||||
}
|
|
||||||
sb.AppendLine("TimeLeft".Translate() + ": " + ticksRemaining.ToStringTicksToPeriod());
|
sb.AppendLine("TimeLeft".Translate() + ": " + ticksRemaining.ToStringTicksToPeriod());
|
||||||
|
var maintenanceNeed = Occupant.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
if (maintenanceNeed != null)
|
||||||
|
{
|
||||||
|
// 直接显示 CurLevel,确保与 Need 显示一致
|
||||||
|
sb.AppendLine("WULA_MaintenanceLevel".Translate() + ": " + maintenanceNeed.CurLevel.ToStringPercent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PowerOn)
|
if (!PowerOn)
|
||||||
{
|
{
|
||||||
sb.AppendLine("NoPower".Translate().Colorize(Color.red));
|
sb.AppendLine("NoPower".Translate().Colorize(Color.red));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString().TrimEnd();
|
return sb.ToString().TrimEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||||
{
|
{
|
||||||
foreach (var gizmo in base.CompGetGizmosExtra())
|
foreach (var gizmo in base.CompGetGizmosExtra())
|
||||||
{
|
{
|
||||||
yield return gizmo;
|
yield return gizmo;
|
||||||
}
|
}
|
||||||
|
// 进入维护舱的按钮
|
||||||
if (state == MaintenancePodState.Idle && PowerOn)
|
if (state == MaintenancePodState.Idle && PowerOn)
|
||||||
{
|
{
|
||||||
var enterCommand = new Command_Action
|
yield return new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "WULA_MaintenancePod_Enter".Translate(),
|
defaultLabel = "WULA_MaintenancePod_Enter".Translate(),
|
||||||
defaultDesc = "WULA_MaintenancePod_EnterDesc".Translate(),
|
defaultDesc = "WULA_MaintenancePod_EnterDesc".Translate(),
|
||||||
icon = EnterIcon,
|
icon = EnterIcon,
|
||||||
action = () =>
|
action = () => ShowPawnSelectionMenu()
|
||||||
{
|
|
||||||
List<FloatMenuOption> options = GetPawnOptions();
|
|
||||||
if (options.Any())
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add(new FloatMenu(options));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Messages.Message("WULA_MaintenancePod_NoOneNeeds".Translate(), MessageTypeDefOf.RejectInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
yield return enterCommand;
|
|
||||||
}
|
}
|
||||||
|
// 取消维护的按钮
|
||||||
if (state == MaintenancePodState.Running)
|
if (state == MaintenancePodState.Running)
|
||||||
{
|
{
|
||||||
var cancelCommand = new Command_Action
|
yield return new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "CommandCancelConstructionLabel".Translate(),
|
defaultLabel = "CommandCancelConstructionLabel".Translate(),
|
||||||
defaultDesc = "WULA_MaintenancePod_CancelDesc".Translate(),
|
defaultDesc = "WULA_MaintenancePod_CancelDesc".Translate(),
|
||||||
icon = CancelIcon,
|
icon = CancelIcon,
|
||||||
action = () =>
|
action = () =>
|
||||||
{
|
{
|
||||||
EjectPawn();
|
EjectPawn(true);
|
||||||
Messages.Message("WULA_MaintenanceCanceled".Translate(), MessageTypeDefOf.NegativeEvent);
|
Messages.Message("WULA_MaintenanceCanceled".Translate(), MessageTypeDefOf.NegativeEvent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
yield return cancelCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEV GIZMO
|
|
||||||
if (DebugSettings.godMode && state == MaintenancePodState.Running)
|
|
||||||
{
|
|
||||||
var finishCommand = new Command_Action
|
|
||||||
{
|
|
||||||
defaultLabel = "DEV: Finish Cycle",
|
|
||||||
action = () =>
|
|
||||||
{
|
|
||||||
Log.Warning("[WulaPodDebug] DEV: Force finishing cycle.");
|
|
||||||
CycleFinished();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
yield return finishCommand;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void ShowPawnSelectionMenu()
|
||||||
|
{
|
||||||
|
var options = GetPawnOptions();
|
||||||
|
if (options.Any())
|
||||||
|
{
|
||||||
|
Find.WindowStack.Add(new FloatMenu(options));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_MaintenancePod_NoOneNeeds".Translate(), MessageTypeDefOf.RejectInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
private List<FloatMenuOption> GetPawnOptions()
|
private List<FloatMenuOption> GetPawnOptions()
|
||||||
{
|
{
|
||||||
List<FloatMenuOption> options = new List<FloatMenuOption>();
|
var options = new List<FloatMenuOption>();
|
||||||
// Now iterates over all pawns on the map, not just colonists.
|
var map = parent.Map;
|
||||||
foreach (Pawn p in parent.Map.mapPawns.AllPawns.Where(pawn => pawn.def.defName == "WulaSpecies" || pawn.def.defName == "WulaSpeciesReal"))
|
|
||||||
{
|
|
||||||
if (p.health.hediffSet.HasHediff(Props.hediffToRemove))
|
|
||||||
{
|
|
||||||
// If the pawn is downed or not a free colonist, they need to be brought to the pod.
|
|
||||||
if (p.Downed || !p.IsFreeColonist)
|
|
||||||
{
|
|
||||||
float required = RequiredComponents(p);
|
|
||||||
if (refuelableComp.Fuel < required)
|
|
||||||
{
|
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ", " + "WULA_MaintenancePod_NotEnoughComponents".Translate(required.ToString("F0")) + ")", null));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Find colonists who can haul the pawn.
|
|
||||||
var potentialHaulers = parent.Map.mapPawns.FreeColonistsSpawned.Where(colonist =>
|
|
||||||
!colonist.Downed && colonist.CanReserveAndReach(p, PathEndMode.OnCell, Danger.Deadly) && colonist.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly));
|
|
||||||
|
|
||||||
if (!potentialHaulers.Any())
|
foreach (var pawn in map.mapPawns.AllPawnsSpawned)
|
||||||
{
|
{
|
||||||
// If no one can haul, then it's unreachable.
|
// 首先检查是否有维护需求
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ", " + "CannotReach".Translate() + ")", null));
|
var maintenanceNeed = pawn.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
}
|
if (maintenanceNeed == null)
|
||||||
else
|
{
|
||||||
{
|
// 这个Pawn没有维护需求,跳过
|
||||||
Action action = delegate
|
continue;
|
||||||
{
|
|
||||||
// Create a menu to select which colonist should do the hauling.
|
|
||||||
var haulerOptions = new List<FloatMenuOption>();
|
|
||||||
foreach (var hauler in potentialHaulers)
|
|
||||||
{
|
|
||||||
haulerOptions.Add(new FloatMenuOption(hauler.LabelCap, delegate
|
|
||||||
{
|
|
||||||
var haulJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_HaulToMaintenancePod, p, parent);
|
|
||||||
haulJob.count = 1;
|
|
||||||
hauler.jobs.TryTakeOrderedJob(haulJob, JobTag.Misc);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
Find.WindowStack.Add(new FloatMenu(haulerOptions));
|
|
||||||
};
|
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap + " (" + p.KindLabel + ")", action));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the pawn is a free colonist and can walk, they can go on their own.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!p.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
|
|
||||||
{
|
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap + " (" + "CannotReach".Translate() + ")", null));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float required = RequiredComponents(p);
|
|
||||||
if (refuelableComp.Fuel >= required)
|
|
||||||
{
|
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap, () =>
|
|
||||||
{
|
|
||||||
Job job = JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, parent);
|
|
||||||
p.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
options.Add(new FloatMenuOption(p.LabelShortCap + " (" + "WULA_MaintenancePod_NotEnoughComponents".Translate(required.ToString("F0")) + ")", null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否真的需要维护
|
||||||
|
if (maintenanceNeed.CurLevel > Props.minNeedLevelToMaintain && !DebugSettings.godMode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 创建选项
|
||||||
|
var option = CreatePawnOption(pawn, maintenanceNeed);
|
||||||
|
if (option != null)
|
||||||
|
options.Add(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private FloatMenuOption CreatePawnOption(Pawn pawn, Need_Maintenance need)
|
||||||
|
{
|
||||||
|
string label = $"{pawn.LabelShortCap} ({need.CurLevel.ToStringPercent()})";
|
||||||
|
float requiredComponents = RequiredComponents;
|
||||||
|
// 检查组件是否足够
|
||||||
|
if (refuelableComp.Fuel < requiredComponents)
|
||||||
|
{
|
||||||
|
return new FloatMenuOption(label + " (" + "WULA_MaintenancePod_NotEnoughComponents".Translate(requiredComponents.ToString("F0")) + ")", null);
|
||||||
|
}
|
||||||
|
// 检查是否可以到达
|
||||||
|
if (!pawn.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
|
||||||
|
{
|
||||||
|
return new FloatMenuOption(label + " (" + "CannotReach".Translate() + ")", null);
|
||||||
|
}
|
||||||
|
return new FloatMenuOption(label, () =>
|
||||||
|
{
|
||||||
|
if (pawn.Downed || !pawn.IsFreeColonist)
|
||||||
|
{
|
||||||
|
// 需要搬运
|
||||||
|
var haulJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_HaulToMaintenancePod, pawn, parent);
|
||||||
|
var hauler = FindBestHauler(pawn);
|
||||||
|
if (hauler != null)
|
||||||
|
{
|
||||||
|
hauler.jobs.TryTakeOrderedJob(haulJob);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_NoHaulerAvailable".Translate(), MessageTypeDefOf.RejectInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 自己进入
|
||||||
|
var enterJob = JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, parent);
|
||||||
|
pawn.jobs.TryTakeOrderedJob(enterJob);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private Pawn FindBestHauler(Pawn target)
|
||||||
|
{
|
||||||
|
return parent.Map.mapPawns.FreeColonistsSpawned
|
||||||
|
.Where(colonist => !colonist.Downed &&
|
||||||
|
colonist.CanReserveAndReach(target, PathEndMode.OnCell, Danger.Deadly) &&
|
||||||
|
colonist.CanReserveAndReach(parent, PathEndMode.InteractionCell, Danger.Deadly))
|
||||||
|
.OrderBy(colonist => colonist.Position.DistanceTo(target.Position))
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
public enum MaintenancePodState
|
public enum MaintenancePodState
|
||||||
{
|
{
|
||||||
Idle,
|
Idle,
|
||||||
Running,
|
Running
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// HediffComp_MaintenanceDamage.cs
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class HediffCompProperties_MaintenanceDamage : HediffCompProperties
|
||||||
|
{
|
||||||
|
public float damageToMaintenanceFactor = 0.01f; // 每点伤害扣除的维护度比例
|
||||||
|
|
||||||
|
public HediffCompProperties_MaintenanceDamage()
|
||||||
|
{
|
||||||
|
compClass = typeof(HediffComp_MaintenanceDamage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HediffComp_MaintenanceDamage : HediffComp
|
||||||
|
{
|
||||||
|
private HediffCompProperties_MaintenanceDamage Props => (HediffCompProperties_MaintenanceDamage)props;
|
||||||
|
|
||||||
|
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||||
|
{
|
||||||
|
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
|
||||||
|
|
||||||
|
// 获取维护需求
|
||||||
|
var maintenanceNeed = Pawn.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
if (maintenanceNeed == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 直接应用伤害惩罚
|
||||||
|
maintenanceNeed.ApplyDamagePenalty(totalDamageDealt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CompTipStringExtra => "WULA_DamageAffectsMaintenance".Translate(Props.damageToMaintenanceFactor.ToStringPercent());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using Verse;
|
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
|
||||||
{
|
|
||||||
public class HediffCompProperties_MaintenanceNeed : HediffCompProperties
|
|
||||||
{
|
|
||||||
public float severityPerDayBeforeThreshold = 0.0f;
|
|
||||||
public float severityPerDayAfterThreshold = 0.0f;
|
|
||||||
public float thresholdDays = 0.0f;
|
|
||||||
|
|
||||||
public HediffCompProperties_MaintenanceNeed()
|
|
||||||
{
|
|
||||||
compClass = typeof(HediffComp_MaintenanceNeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HediffComp_MaintenanceNeed : HediffComp
|
|
||||||
{
|
|
||||||
private HediffCompProperties_MaintenanceNeed Props => (HediffCompProperties_MaintenanceNeed)props;
|
|
||||||
|
|
||||||
public override void CompPostTick(ref float severityAdjustment)
|
|
||||||
{
|
|
||||||
base.CompPostTick(ref severityAdjustment);
|
|
||||||
|
|
||||||
// We adjust severity once per game day (60000 ticks)
|
|
||||||
if (parent.ageTicks % 60000 == 0)
|
|
||||||
{
|
|
||||||
float ageInDays = (float)parent.ageTicks / 60000f;
|
|
||||||
if (ageInDays < Props.thresholdDays)
|
|
||||||
{
|
|
||||||
severityAdjustment += Props.severityPerDayBeforeThreshold;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
severityAdjustment += Props.severityPerDayAfterThreshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using RimWorld;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
|
||||||
{
|
|
||||||
[DefOf]
|
|
||||||
public static class JobDefOf_WULA
|
|
||||||
{
|
|
||||||
public static JobDef WULA_EnterMaintenancePod;
|
|
||||||
|
|
||||||
public static JobDef WULA_HaulToMaintenancePod;
|
|
||||||
|
|
||||||
static JobDefOf_WULA()
|
|
||||||
{
|
|
||||||
DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf_WULA));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
// JobDriver_EnterMaintenancePod.cs (更新版)
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Verse;
|
using Verse;
|
||||||
using Verse.AI;
|
using Verse.AI;
|
||||||
@@ -11,6 +11,7 @@ namespace WulaFallenEmpire
|
|||||||
private const TargetIndex PodIndex = TargetIndex.A;
|
private const TargetIndex PodIndex = TargetIndex.A;
|
||||||
|
|
||||||
protected Thing Pod => job.GetTarget(PodIndex).Thing;
|
protected Thing Pod => job.GetTarget(PodIndex).Thing;
|
||||||
|
protected CompMaintenancePod PodComp => Pod?.TryGetComp<CompMaintenancePod>();
|
||||||
|
|
||||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
{
|
{
|
||||||
@@ -19,29 +20,24 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
protected override IEnumerable<Toil> MakeNewToils()
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] JobDriver_EnterMaintenancePod started for pawn: {pawn.LabelShortCap}");
|
|
||||||
this.FailOnDespawnedNullOrForbidden(PodIndex);
|
this.FailOnDespawnedNullOrForbidden(PodIndex);
|
||||||
this.FailOnBurningImmobile(PodIndex);
|
this.FailOn(() => PodComp == null || PodComp.State != MaintenancePodState.Idle || !PodComp.PowerOn);
|
||||||
|
|
||||||
var podComp = Pod.TryGetComp<CompMaintenancePod>();
|
// 移动到维护舱
|
||||||
this.FailOn(() => podComp == null || podComp.State != MaintenancePodState.Idle || !podComp.PowerOn);
|
yield return Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
|
||||||
|
|
||||||
// Go to the pod's interaction cell
|
// 进入维护舱
|
||||||
Toil goToPod = Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
|
yield return new Toil
|
||||||
goToPod.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] EnterJob: Pawn {pawn.LabelShortCap} is going to the pod."));
|
|
||||||
yield return goToPod;
|
|
||||||
|
|
||||||
// Enter the pod
|
|
||||||
Toil enterToil = new Toil
|
|
||||||
{
|
{
|
||||||
initAction = () =>
|
initAction = () =>
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] EnterJob: Pawn {pawn.LabelShortCap} has arrived and is entering the pod.");
|
if (PodComp != null)
|
||||||
podComp.StartCycle(pawn);
|
{
|
||||||
|
PodComp.StartCycle(pawn);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
defaultCompleteMode = ToilCompleteMode.Instant
|
defaultCompleteMode = ToilCompleteMode.Instant
|
||||||
};
|
};
|
||||||
yield return enterToil;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// JobDriver_HaulToMaintenancePod.cs (修复版)
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using Verse;
|
using Verse;
|
||||||
@@ -12,52 +13,70 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
protected Pawn Takee => (Pawn)job.GetTarget(TakeeIndex).Thing;
|
protected Pawn Takee => (Pawn)job.GetTarget(TakeeIndex).Thing;
|
||||||
protected Building Pod => (Building)job.GetTarget(PodIndex).Thing;
|
protected Building Pod => (Building)job.GetTarget(PodIndex).Thing;
|
||||||
protected CompMaintenancePod PodComp => Pod.TryGetComp<CompMaintenancePod>();
|
protected CompMaintenancePod PodComp => Pod?.TryGetComp<CompMaintenancePod>();
|
||||||
|
|
||||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
{
|
{
|
||||||
|
// 修复:明确指定计数为1
|
||||||
return pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)
|
return pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)
|
||||||
&& pawn.Reserve(Pod, job, 1, -1, null, errorOnFailed);
|
&& pawn.Reserve(Pod, job, 1, -1, null, errorOnFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<Toil> MakeNewToils()
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] JobDriver_HaulToMaintenancePod started. Hauler: {pawn.LabelShortCap}, Takee: {Takee.LabelShortCap}");
|
|
||||||
// Standard failure conditions
|
|
||||||
this.FailOnDestroyedOrNull(TakeeIndex);
|
this.FailOnDestroyedOrNull(TakeeIndex);
|
||||||
this.FailOnDestroyedOrNull(PodIndex);
|
this.FailOnDestroyedOrNull(PodIndex);
|
||||||
this.FailOnAggroMentalStateAndHostile(TakeeIndex);
|
this.FailOn(() => PodComp == null || PodComp.State != MaintenancePodState.Idle);
|
||||||
this.FailOn(() => PodComp == null);
|
|
||||||
this.FailOn(() => !pawn.CanReach(Pod, PathEndMode.InteractionCell, Danger.Deadly));
|
|
||||||
this.FailOn(() => !Takee.Downed);
|
|
||||||
|
|
||||||
// Go to the pawn to be rescued
|
// 前往目标 pawn
|
||||||
Toil goToTakee = Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch)
|
yield return Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch);
|
||||||
.FailOnDespawnedNullOrForbidden(TakeeIndex)
|
|
||||||
.FailOnDespawnedNullOrForbidden(PodIndex)
|
|
||||||
.FailOnSomeonePhysicallyInteracting(TakeeIndex);
|
|
||||||
goToTakee.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is going to pick up {Takee.LabelShortCap}."));
|
|
||||||
yield return goToTakee;
|
|
||||||
|
|
||||||
// Start carrying the pawn
|
// 开始搬运 - 修复计数问题
|
||||||
Toil startCarrying = Toils_Haul.StartCarryThing(TakeeIndex, false, true, false);
|
yield return new Toil
|
||||||
startCarrying.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is now carrying {Takee.LabelShortCap}."));
|
|
||||||
yield return startCarrying;
|
|
||||||
|
|
||||||
// Go to the maintenance pod
|
|
||||||
Toil goToPod = Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
|
|
||||||
goToPod.AddPreInitAction(() => Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} is hauling {Takee.LabelShortCap} to the pod."));
|
|
||||||
yield return goToPod;
|
|
||||||
|
|
||||||
// Place the pawn inside the pod
|
|
||||||
Toil placeInPod = ToilMaker.MakeToil("PlaceInPod");
|
|
||||||
placeInPod.initAction = delegate
|
|
||||||
{
|
{
|
||||||
Log.Warning($"[WulaPodDebug] HaulJob: {pawn.LabelShortCap} has arrived and is placing {Takee.LabelShortCap} in the pod.");
|
initAction = () =>
|
||||||
PodComp.StartCycle(Takee);
|
{
|
||||||
|
// 明确设置搬运数量为1
|
||||||
|
if (pawn.carryTracker.CarriedThing == null)
|
||||||
|
{
|
||||||
|
if (Takee == null || Takee.Destroyed)
|
||||||
|
{
|
||||||
|
Log.Error("试图搬运不存在的Pawn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用TryStartCarryThing并明确指定数量
|
||||||
|
if (pawn.carryTracker.TryStartCarry(Takee, 1) <= 0)
|
||||||
|
{
|
||||||
|
Log.Error($"无法搬运Pawn: {Takee.Label}");
|
||||||
|
EndJobWith(JobCondition.Incompletable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultCompleteMode = ToilCompleteMode.Instant
|
||||||
|
};
|
||||||
|
|
||||||
|
// 前往维护舱
|
||||||
|
yield return Toils_Goto.GotoThing(PodIndex, PathEndMode.InteractionCell);
|
||||||
|
|
||||||
|
// 放入维护舱
|
||||||
|
yield return new Toil
|
||||||
|
{
|
||||||
|
initAction = () =>
|
||||||
|
{
|
||||||
|
if (PodComp != null && Takee != null)
|
||||||
|
{
|
||||||
|
// 确保Pawn被放下
|
||||||
|
if (pawn.carryTracker.CarriedThing == Takee)
|
||||||
|
{
|
||||||
|
pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
PodComp.StartCycle(Takee);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultCompleteMode = ToilCompleteMode.Instant
|
||||||
};
|
};
|
||||||
placeInPod.defaultCompleteMode = ToilCompleteMode.Instant;
|
|
||||||
yield return placeInPod;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using RimWorld;
|
|
||||||
using Verse;
|
|
||||||
using Verse.AI;
|
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
|
||||||
{
|
|
||||||
public class WorkGiver_DoMaintenance : WorkGiver_Scanner
|
|
||||||
{
|
|
||||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WULA_MaintenancePod"));
|
|
||||||
|
|
||||||
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
|
||||||
{
|
|
||||||
return pawn.CanReserve(t, 1, -1, null, forced);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
|
||||||
{
|
|
||||||
return JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_EnterMaintenancePod"), t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// MaintenanceNeedExtension.cs
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class MaintenanceNeedExtension : DefModExtension
|
||||||
|
{
|
||||||
|
// 基础退化设置
|
||||||
|
public float severityPerDayBeforeThreshold = 0.05f;
|
||||||
|
public float severityPerDayAfterThreshold = 0.1f;
|
||||||
|
public float thresholdDays = 5f;
|
||||||
|
|
||||||
|
// 状态阈值
|
||||||
|
public float minorBreakdownThreshold = 0.3f;
|
||||||
|
public float majorBreakdownThreshold = 0.1f;
|
||||||
|
public float criticalFailureThreshold = 0.01f;
|
||||||
|
|
||||||
|
// 伤害相关设置 - 简化
|
||||||
|
public float damageToMaintenanceFactor = 0.01f; // 每点伤害扣除的维护度
|
||||||
|
|
||||||
|
// 维护效果相关的 HediffDefs
|
||||||
|
public HediffDef minorBreakdownHediff = null;
|
||||||
|
public HediffDef majorBreakdownHediff = null;
|
||||||
|
public HediffDef criticalFailureHediff = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
// Need_Maintenance.cs
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class Need_Maintenance : Need
|
||||||
|
{
|
||||||
|
private MaintenanceNeedExtension Extension => def.GetModExtension<MaintenanceNeedExtension>();
|
||||||
|
|
||||||
|
// 上次维护的天数
|
||||||
|
private float daysSinceLastMaintenance = 0f;
|
||||||
|
|
||||||
|
// 当前维护状态
|
||||||
|
public MaintenanceStatus Status
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CurLevel <= Extension?.criticalFailureThreshold) return MaintenanceStatus.CriticalFailure;
|
||||||
|
if (CurLevel <= Extension?.majorBreakdownThreshold) return MaintenanceStatus.MajorBreakdown;
|
||||||
|
if (CurLevel <= Extension?.minorBreakdownThreshold) return MaintenanceStatus.MinorBreakdown;
|
||||||
|
return MaintenanceStatus.Operational;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float DaysSinceLastMaintenance => daysSinceLastMaintenance;
|
||||||
|
|
||||||
|
public Need_Maintenance(Pawn pawn) : base(pawn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetInitialLevel()
|
||||||
|
{
|
||||||
|
CurLevel = 1.0f;
|
||||||
|
daysSinceLastMaintenance = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void NeedInterval()
|
||||||
|
{
|
||||||
|
if (pawn.Dead || !pawn.Spawned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 每150 ticks 更新一次(Need 的标准间隔)
|
||||||
|
if (IsFrozen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 增加天数计数
|
||||||
|
daysSinceLastMaintenance += 150f / 60000f; // 150 ticks 占一天的比例
|
||||||
|
|
||||||
|
// 计算退化速率
|
||||||
|
float degradationRate = CalculateDegradationRate();
|
||||||
|
|
||||||
|
// 应用退化
|
||||||
|
CurLevel -= degradationRate * (150f / 60000f); // 转换为每天的比例
|
||||||
|
|
||||||
|
// 确保数值在有效范围内
|
||||||
|
CurLevel = ClampNeedLevel(CurLevel);
|
||||||
|
|
||||||
|
// 检查状态变化
|
||||||
|
CheckStatusChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateDegradationRate()
|
||||||
|
{
|
||||||
|
if (Extension == null)
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
if (daysSinceLastMaintenance < Extension.thresholdDays)
|
||||||
|
{
|
||||||
|
return Extension.severityPerDayBeforeThreshold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Extension.severityPerDayAfterThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckStatusChanges()
|
||||||
|
{
|
||||||
|
if (Extension == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 检查是否需要应用故障效果
|
||||||
|
var currentStatus = Status;
|
||||||
|
|
||||||
|
// 移除旧的维护相关 Hediff
|
||||||
|
RemoveMaintenanceHediffs();
|
||||||
|
|
||||||
|
// 根据状态添加相应的 Hediff
|
||||||
|
switch (currentStatus)
|
||||||
|
{
|
||||||
|
case MaintenanceStatus.MinorBreakdown:
|
||||||
|
if (Extension.minorBreakdownHediff != null)
|
||||||
|
pawn.health.AddHediff(Extension.minorBreakdownHediff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MaintenanceStatus.MajorBreakdown:
|
||||||
|
if (Extension.majorBreakdownHediff != null)
|
||||||
|
pawn.health.AddHediff(Extension.majorBreakdownHediff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MaintenanceStatus.CriticalFailure:
|
||||||
|
if (Extension.criticalFailureHediff != null)
|
||||||
|
pawn.health.AddHediff(Extension.criticalFailureHediff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveMaintenanceHediffs()
|
||||||
|
{
|
||||||
|
if (Extension == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 移除所有维护相关的 Hediff
|
||||||
|
var hediffsToRemove = pawn.health.hediffSet.hediffs.FindAll(h =>
|
||||||
|
h.def == Extension.minorBreakdownHediff ||
|
||||||
|
h.def == Extension.majorBreakdownHediff ||
|
||||||
|
h.def == Extension.criticalFailureHediff);
|
||||||
|
|
||||||
|
foreach (var hediff in hediffsToRemove)
|
||||||
|
{
|
||||||
|
pawn.health.RemoveHediff(hediff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行维护操作
|
||||||
|
public void PerformMaintenance(float maintenanceAmount = 1.0f)
|
||||||
|
{
|
||||||
|
CurLevel += maintenanceAmount;
|
||||||
|
CurLevel = ClampNeedLevel(CurLevel);
|
||||||
|
daysSinceLastMaintenance = 0f;
|
||||||
|
|
||||||
|
// 移除所有维护相关的负面效果
|
||||||
|
RemoveMaintenanceHediffs();
|
||||||
|
|
||||||
|
// 触发维护完成的效果
|
||||||
|
OnMaintenancePerformed(maintenanceAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用伤害惩罚 - 简单的线性减少
|
||||||
|
public void ApplyDamagePenalty(float damageAmount)
|
||||||
|
{
|
||||||
|
if (Extension == null) return;
|
||||||
|
|
||||||
|
// 直接线性减少维护度
|
||||||
|
float reduction = damageAmount * Extension.damageToMaintenanceFactor;
|
||||||
|
CurLevel = Math.Max(0f, CurLevel - reduction);
|
||||||
|
|
||||||
|
// 立即检查状态变化
|
||||||
|
CheckStatusChanges();
|
||||||
|
|
||||||
|
if (pawn.IsColonistPlayerControlled && reduction > 0.01f)
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_MaintenanceReducedDueToDamage".Translate(pawn.LabelShort, reduction.ToStringPercent()),
|
||||||
|
pawn, MessageTypeDefOf.NegativeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMaintenancePerformed(float amount)
|
||||||
|
{
|
||||||
|
// 这里可以添加维护完成时的特殊效果
|
||||||
|
if (pawn.IsColonistPlayerControlled)
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_MaintenanceCompleted".Translate(pawn.LabelShort), pawn, MessageTypeDefOf.PositiveEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float ClampNeedLevel(float level)
|
||||||
|
{
|
||||||
|
return level < 0f ? 0f : (level > 1f ? 1f : level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetTipString()
|
||||||
|
{
|
||||||
|
string baseTip = base.GetTipString();
|
||||||
|
|
||||||
|
string statusText = "WULA_MaintenanceStatus".Translate(Status.GetLabel(), daysSinceLastMaintenance.ToString("F1"));
|
||||||
|
string degradationText = "WULA_DegradationRate".Translate(CalculateDegradationRate().ToString("F3"));
|
||||||
|
|
||||||
|
return $"{baseTip}\n\n{statusText}\n{degradationText}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
Scribe_Values.Look(ref daysSinceLastMaintenance, "daysSinceLastMaintenance", 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 维护状态枚举
|
||||||
|
public enum MaintenanceStatus
|
||||||
|
{
|
||||||
|
Operational,
|
||||||
|
MinorBreakdown,
|
||||||
|
MajorBreakdown,
|
||||||
|
CriticalFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MaintenanceStatusExtensions
|
||||||
|
{
|
||||||
|
public static string GetLabel(this MaintenanceStatus status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case MaintenanceStatus.Operational:
|
||||||
|
return "WULA_Operational".Translate();
|
||||||
|
case MaintenanceStatus.MinorBreakdown:
|
||||||
|
return "WULA_MinorBreakdown".Translate();
|
||||||
|
case MaintenanceStatus.MajorBreakdown:
|
||||||
|
return "WULA_MajorBreakdown".Translate();
|
||||||
|
case MaintenanceStatus.CriticalFailure:
|
||||||
|
return "WULA_CriticalFailure".Translate();
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDescription(this MaintenanceStatus status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case MaintenanceStatus.Operational:
|
||||||
|
return "WULA_OperationalDesc".Translate();
|
||||||
|
case MaintenanceStatus.MinorBreakdown:
|
||||||
|
return "WULA_MinorBreakdownDesc".Translate();
|
||||||
|
case MaintenanceStatus.MajorBreakdown:
|
||||||
|
return "WULA_MajorBreakdownDesc".Translate();
|
||||||
|
case MaintenanceStatus.CriticalFailure:
|
||||||
|
return "WULA_CriticalFailureDesc".Translate();
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// WorkGiver_DoMaintenance.cs (修复版)
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class WorkGiver_DoMaintenance : WorkGiver_Scanner
|
||||||
|
{
|
||||||
|
public override ThingRequest PotentialWorkThingRequest =>
|
||||||
|
ThingRequest.ForDef(ThingDef.Named("WULA_MaintenancePod"));
|
||||||
|
|
||||||
|
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||||
|
|
||||||
|
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
// 检查维护舱是否可用
|
||||||
|
if (!pawn.CanReserve(t, 1, -1, null, forced))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var podComp = t.TryGetComp<CompMaintenancePod>();
|
||||||
|
if (podComp == null || podComp.State != MaintenancePodState.Idle || !podComp.PowerOn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查当前pawn是否有维护需求且需要维护
|
||||||
|
return PawnNeedsMaintenance(pawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
return JobMaker.MakeJob(JobDefOf_WULA.WULA_EnterMaintenancePod, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查单个Pawn是否需要维护
|
||||||
|
private bool PawnNeedsMaintenance(Pawn pawn)
|
||||||
|
{
|
||||||
|
// 检查是否有维护需求组件
|
||||||
|
var maintenanceNeed = pawn.needs?.TryGetNeed<Need_Maintenance>();
|
||||||
|
if (maintenanceNeed == null)
|
||||||
|
{
|
||||||
|
// 这个Pawn没有维护需求,不应该使用维护舱
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查维护水平是否低于阈值
|
||||||
|
return maintenanceNeed.CurLevel <= 0.3f; // 需要维护的阈值
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,4 +15,16 @@ namespace WulaFallenEmpire
|
|||||||
DefOfHelper.EnsureInitializedInCtor(typeof(ThingDefOf_WULA));
|
DefOfHelper.EnsureInitializedInCtor(typeof(ThingDefOf_WULA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[DefOf]
|
||||||
|
public static class JobDefOf_WULA
|
||||||
|
{
|
||||||
|
public static JobDef WULA_EnterMaintenancePod;
|
||||||
|
|
||||||
|
public static JobDef WULA_HaulToMaintenancePod;
|
||||||
|
|
||||||
|
static JobDefOf_WULA()
|
||||||
|
{
|
||||||
|
DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf_WULA));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -106,6 +106,11 @@
|
|||||||
<Compile Include="Flyover\WULA_ShipArtillery\CompShipArtillery.cs" />
|
<Compile Include="Flyover\WULA_ShipArtillery\CompShipArtillery.cs" />
|
||||||
<Compile Include="Flyover\WULA_SpawnFlyOver\CompAbilityEffect_SpawnFlyOver.cs" />
|
<Compile Include="Flyover\WULA_SpawnFlyOver\CompAbilityEffect_SpawnFlyOver.cs" />
|
||||||
<Compile Include="Flyover\WULA_SpawnFlyOver\CompProperties_AbilitySpawnFlyOver.cs" />
|
<Compile Include="Flyover\WULA_SpawnFlyOver\CompProperties_AbilitySpawnFlyOver.cs" />
|
||||||
|
<Compile Include="GlobalWorkTable\Building_GlobalWorkTable.cs" />
|
||||||
|
<Compile Include="GlobalWorkTable\GlobalProductionOrder.cs" />
|
||||||
|
<Compile Include="GlobalWorkTable\GlobalProductionOrderStack.cs" />
|
||||||
|
<Compile Include="GlobalWorkTable\GlobalStorageWorldComponent.cs" />
|
||||||
|
<Compile Include="GlobalWorkTable\ITab_GlobalBills.cs" />
|
||||||
<Compile Include="HediffComp\HediffCompProperties_NanoRepair.cs" />
|
<Compile Include="HediffComp\HediffCompProperties_NanoRepair.cs" />
|
||||||
<Compile Include="HediffComp\WULA_HediffDamgeShield\DRMDamageShield.cs" />
|
<Compile Include="HediffComp\WULA_HediffDamgeShield\DRMDamageShield.cs" />
|
||||||
<Compile Include="HediffComp\WULA_HediffDamgeShield\Hediff_DamageShield.cs" />
|
<Compile Include="HediffComp\WULA_HediffDamgeShield\Hediff_DamageShield.cs" />
|
||||||
@@ -142,11 +147,12 @@
|
|||||||
<Compile Include="Pawn\WULA_Energy\WulaStatDefOf.cs" />
|
<Compile Include="Pawn\WULA_Energy\WulaStatDefOf.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\Building_MaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\Building_MaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\CompMaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\CompMaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\HediffComp_MaintenanceNeed.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\HediffCompProperties_MaintenanceDamage.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\JobDefOf_WULA.cs" />
|
|
||||||
<Compile Include="Pawn\WULA_Maintenance\JobDriver_EnterMaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\JobDriver_EnterMaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\JobDriver_HaulToMaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\JobDriver_HaulToMaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\Job_Maintenance.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\MaintenanceNeedExtension.cs" />
|
||||||
|
<Compile Include="Pawn\WULA_Maintenance\Need_Maintenance.cs" />
|
||||||
|
<Compile Include="Pawn\WULA_Maintenance\WorkGiver_DoMaintenance.cs" />
|
||||||
<Compile Include="ThingComp\CompAndPatch_GiveHediffOnShot.cs" />
|
<Compile Include="ThingComp\CompAndPatch_GiveHediffOnShot.cs" />
|
||||||
<Compile Include="ThingComp\CompApparelInterceptor.cs" />
|
<Compile Include="ThingComp\CompApparelInterceptor.cs" />
|
||||||
<Compile Include="ThingComp\CompPsychicScaling.cs" />
|
<Compile Include="ThingComp\CompPsychicScaling.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user