This commit is contained in:
2025-10-01 13:24:42 +08:00
parent 914879ebd3
commit 4c0c8e7635
10 changed files with 349 additions and 110 deletions

Binary file not shown.

View File

@@ -59,8 +59,11 @@
</statBases> </statBases>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ApparelOnSkinBase"> <ThingDef ParentName="ARA_ApparelOnSkinBase">
@@ -88,8 +91,11 @@
</statBases> </statBases>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ApparelOnSkinBase"> <ThingDef ParentName="ARA_ApparelOnSkinBase">
@@ -117,8 +123,11 @@
</statBases> </statBases>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ApparelOnSkinBase"> <ThingDef ParentName="ARA_ApparelOnSkinBase">
@@ -146,8 +155,11 @@
</statBases> </statBases>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ApparelOnSkinBase"> <ThingDef ParentName="ARA_ApparelOnSkinBase">
@@ -175,8 +187,11 @@
</statBases> </statBases>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
@@ -300,8 +315,11 @@
<hediff>ARA_TerrainWorkSpeedHediff</hediff> <hediff>ARA_TerrainWorkSpeedHediff</hediff>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ClothBase"> <ThingDef ParentName="ARA_ClothBase">
@@ -347,8 +365,11 @@
<hediff>ARA_TerrainMoveSpeedHediff</hediff> <hediff>ARA_TerrainMoveSpeedHediff</hediff>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ClothBase"> <ThingDef ParentName="ARA_ClothBase">
@@ -395,8 +416,11 @@
<hediff>ARA_TerrainHealHediff</hediff> <hediff>ARA_TerrainHealHediff</hediff>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ClothBase"> <ThingDef ParentName="ARA_ClothBase">
@@ -443,8 +467,11 @@
<hediff>ARA_TerrainTemptHediff</hediff> <hediff>ARA_TerrainTemptHediff</hediff>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="ARA_ClothBase"> <ThingDef ParentName="ARA_ClothBase">
@@ -491,8 +518,11 @@
<hediff>ARA_TerrainTerrorRoar_Hediff</hediff> <hediff>ARA_TerrainTerrorRoar_Hediff</hediff>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Cloth_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Cloth_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>

View File

@@ -170,8 +170,11 @@
</tools> </tools>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot"> <li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot">
<hediffDef>ARA_ChainReload</hediffDef> <hediffDef>ARA_ChainReload</hediffDef>
<severityToAdd>0.2</severityToAdd> <severityToAdd>0.2</severityToAdd>
@@ -251,8 +254,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot"> <li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot">
<hediffDef>ARA_ChainReload</hediffDef> <hediffDef>ARA_ChainReload</hediffDef>
<severityToAdd>0.1</severityToAdd> <severityToAdd>0.1</severityToAdd>

View File

@@ -70,8 +70,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ThingDef ParentName="BaseMeleeWeapon_Sharp_Quality"> <ThingDef ParentName="BaseMeleeWeapon_Sharp_Quality">
@@ -136,8 +139,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
</comps> </comps>
</ThingDef> </ThingDef>
<ToolCapacityDef> <ToolCapacityDef>
@@ -211,8 +217,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_Cleave"> <li Class="ArachnaeSwarm.CompProperties_Cleave">
<cleaveAngle>90</cleaveAngle> <cleaveAngle>90</cleaveAngle>
<cleaveRange>2.5</cleaveRange> <cleaveRange>2.5</cleaveRange>
@@ -329,8 +338,11 @@
</tools> </tools>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Toxid</li> <li>ARA_Weapon_Damage_Toxid</li>
@@ -430,8 +442,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Toxid</li> <li>ARA_Weapon_Damage_Toxid</li>
@@ -505,8 +520,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Toxid</li> <li>ARA_Weapon_Damage_Toxid</li>
@@ -578,8 +596,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot"> <li Class="ArachnaeSwarm.CompProperties_GiveHediffOnShot">
<hediffDef>ARA_ChainReload</hediffDef> <hediffDef>ARA_ChainReload</hediffDef>
<severityToAdd>1</severityToAdd> <severityToAdd>1</severityToAdd>
@@ -679,8 +700,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Acid</li> <li>ARA_Weapon_Damage_Acid</li>
@@ -787,8 +811,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon"
MayRequire="Ludeon.RimWorld.Odyssey"> MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
@@ -867,8 +894,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Huge_Weapon</li> <li>ARA_Huge_Weapon</li>
@@ -984,8 +1014,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_1Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_1Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Spawn</li> <li>ARA_Weapon_Damage_Spawn</li>

View File

@@ -69,8 +69,11 @@
</thingSetMakerTags> </thingSetMakerTags>
<comps> <comps>
<li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo"> <li Class="ArachnaeSwarm.CompProperties_ExtraIncubationInfo">
<cocoonDef>ARA_Cocoon_Weapon_2Stage</cocoonDef> <cocoonDefs>
</li> <li>ARA_Cocoon_Weapon_2Stage</li>
<li>ARA_BioforgeIncubator_Thing</li>
</cocoonDefs>
</li>
<li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey"> <li Class="ArachnaeSwarm.CompProperties_CustomUniqueWeapon" MayRequire="Ludeon.RimWorld.Odyssey">
<forcedTraits> <forcedTraits>
<li>ARA_Weapon_Damage_Acid</li> <li>ARA_Weapon_Damage_Acid</li>

View File

@@ -325,7 +325,7 @@
<fillPercent>0.8</fillPercent> <fillPercent>0.8</fillPercent>
<interactionCellOffset>(0,0,-1)</interactionCellOffset> <interactionCellOffset>(0,0,-1)</interactionCellOffset>
<hasInteractionCell>true</hasInteractionCell> <hasInteractionCell>true</hasInteractionCell>
<!-- <designationCategory>ARA_Buildings</designationCategory> --> <designationCategory>ARA_Buildings</designationCategory>
<uiOrder>2600</uiOrder> <uiOrder>2600</uiOrder>
<surfaceType>Item</surfaceType> <surfaceType>Item</surfaceType>
<building> <building>
@@ -373,7 +373,7 @@
</li> </li>
</qualityThresholds> </qualityThresholds>
<!-- 生产列表 --> <!-- 生产列表
<processes> <processes>
<li> <li>
<thingDef>ARA_RW_Basic_Acid_Bladder_Gun</thingDef> <thingDef>ARA_RW_Basic_Acid_Bladder_Gun</thingDef>
@@ -387,7 +387,7 @@
<totalNutritionNeeded>10</totalNutritionNeeded> <totalNutritionNeeded>10</totalNutritionNeeded>
<requiredResearch>ARA_Technology_5PAV</requiredResearch> <requiredResearch>ARA_Technology_5PAV</requiredResearch>
</li> </li>
</processes> </processes>-->
</li> </li>
<!-- b. 我们的营养燃料组件 --> <!-- b. 我们的营养燃料组件 -->

View File

@@ -116,37 +116,50 @@ namespace ArachnaeSwarm
if (thingDef.IsApparel || thingDef.IsWeapon) if (thingDef.IsApparel || thingDef.IsWeapon)
{ {
var incubationCompProps = thingDef.GetCompProperties<CompProperties_ExtraIncubationInfo>(); var incubationCompProps = thingDef.GetCompProperties<CompProperties_ExtraIncubationInfo>();
if (incubationCompProps != null && incubationCompProps.cocoonDef == parent.def) if (incubationCompProps != null)
{ {
// 获取研究前提 - 从 recipeMaker 中获取 bool isMatch = false;
ResearchProjectDef researchPrerequisite = null; if (!incubationCompProps.cocoonDefs.NullOrEmpty())
// 方法1从 recipeMaker.researchPrerequisite 获取
if (thingDef.recipeMaker?.researchPrerequisite != null)
{ {
researchPrerequisite = thingDef.recipeMaker.researchPrerequisite; isMatch = incubationCompProps.cocoonDefs.Contains(parent.def);
} }
// 方法2从 recipeMaker.researchPrerequisites 获取第一个 else if (incubationCompProps.cocoonDef != null)
else if (thingDef.recipeMaker?.researchPrerequisites?.Count > 0)
{ {
researchPrerequisite = thingDef.recipeMaker.researchPrerequisites[0]; isMatch = incubationCompProps.cocoonDef == parent.def;
}
// 方法3从 thingDef.researchPrerequisites 获取(备用)
else if (thingDef.researchPrerequisites?.Count > 0)
{
researchPrerequisite = thingDef.researchPrerequisites[0];
} }
// 创建 ProcessDef if (isMatch)
ProcessDef process = new ProcessDef
{ {
thingDef = thingDef, // 获取研究前提 - 从 recipeMaker 中获取
productionTicks = GetIncubationTimeTicks(thingDef), ResearchProjectDef researchPrerequisite = null;
totalNutritionNeeded = GetIncubationCost(thingDef),
requiredResearch = researchPrerequisite // 方法1从 recipeMaker.researchPrerequisite 获取
}; if (thingDef.recipeMaker?.researchPrerequisite != null)
{
researchPrerequisite = thingDef.recipeMaker.researchPrerequisite;
}
// 方法2从 recipeMaker.researchPrerequisites 获取第一个
else if (thingDef.recipeMaker?.researchPrerequisites?.Count > 0)
{
researchPrerequisite = thingDef.recipeMaker.researchPrerequisites[0];
}
// 方法3从 thingDef.researchPrerequisites 获取(备用)
else if (thingDef.researchPrerequisites?.Count > 0)
{
researchPrerequisite = thingDef.researchPrerequisites[0];
}
_cachedProcesses.Add(process); // 创建 ProcessDef
ProcessDef process = new ProcessDef
{
thingDef = thingDef,
productionTicks = GetIncubationTimeTicks(thingDef),
totalNutritionNeeded = GetIncubationCost(thingDef),
requiredResearch = researchPrerequisite
};
_cachedProcesses.Add(process);
}
} }
} }
} }

View File

@@ -11,16 +11,22 @@ namespace ArachnaeSwarm
// Data contract for a single production order in the queue // Data contract for a single production order in the queue
public class QueuedProcessOrder : IExposable public class QueuedProcessOrder : IExposable
{ {
public ProcessDef process; // Using the existing ProcessDef public ProcessDef process;
public int productionUntilTick = -1; public int productionUntilTick = -1;
// Quality-related fields
public int ticksUnderOptimalConditions; public int ticksUnderOptimalConditions;
public float temperaturePenaltyPercent; public float temperaturePenaltyPercent;
// Add a non-saved field to hold the defName during loading
public string tempThingDefName;
public void ExposeData() public void ExposeData()
{ {
Scribe_Deep.Look(ref process, "process"); if (Scribe.mode == LoadSaveMode.Saving)
{
tempThingDefName = process?.thingDef?.defName;
}
Scribe_Values.Look(ref tempThingDefName, "thingDefName");
Scribe_Values.Look(ref productionUntilTick, "productionUntilTick", -1); Scribe_Values.Look(ref productionUntilTick, "productionUntilTick", -1);
Scribe_Values.Look(ref ticksUnderOptimalConditions, "ticksUnderOptimalConditions", 0); Scribe_Values.Look(ref ticksUnderOptimalConditions, "ticksUnderOptimalConditions", 0);
Scribe_Values.Look(ref temperaturePenaltyPercent, "temperaturePenaltyPercent", 0f); Scribe_Values.Look(ref temperaturePenaltyPercent, "temperaturePenaltyPercent", 0f);
@@ -30,12 +36,10 @@ namespace ArachnaeSwarm
// Properties for the new queued producer component // Properties for the new queued producer component
public class CompProperties_QueuedInteractiveProducer : CompProperties public class CompProperties_QueuedInteractiveProducer : CompProperties
{ {
public List<ProcessDef> processes;
public List<PawnKindDef> whitelist; public List<PawnKindDef> whitelist;
public int productionQueueLimit = 1; public int productionQueueLimit = 1;
public float minNutritionToStart = 0.1f; public float minNutritionToStart = 0.1f;
// Quality-related properties from CompInteractiveProducer
public float minSafeTemperature = 7f; public float minSafeTemperature = 7f;
public float maxSafeTemperature = 32f; public float maxSafeTemperature = 32f;
public float penaltyPerDegreePerTick = 0.00001f; public float penaltyPerDegreePerTick = 0.00001f;
@@ -48,24 +52,49 @@ namespace ArachnaeSwarm
} }
} }
// The main component logic [StaticConstructorOnStartup]
public class CompQueuedInteractiveProducer : ThingComp public class CompQueuedInteractiveProducer : ThingComp
{ {
private List<QueuedProcessOrder> productionOrders = new List<QueuedProcessOrder>(); private List<QueuedProcessOrder> productionOrders = new List<QueuedProcessOrder>();
public ProcessDef selectedProcess; // For passing to the JobDriver public ProcessDef selectedProcess;
private CompRefuelableNutrition _fuelComp; private CompRefuelableNutrition _fuelComp;
private CompAffectedByFacilities _facilitiesComp; private CompAffectedByFacilities _facilitiesComp;
private List<ProcessDef> _cachedProcesses;
public CompProperties_QueuedInteractiveProducer Props => (CompProperties_QueuedInteractiveProducer)props; public CompProperties_QueuedInteractiveProducer Props => (CompProperties_QueuedInteractiveProducer)props;
private CompRefuelableNutrition FuelComp => _fuelComp ?? (_fuelComp = parent.GetComp<CompRefuelableNutrition>()); private CompRefuelableNutrition FuelComp => _fuelComp ?? (_fuelComp = parent.GetComp<CompRefuelableNutrition>());
private CompAffectedByFacilities FacilitiesComp => _facilitiesComp ?? (_facilitiesComp = parent.GetComp<CompAffectedByFacilities>()); private CompAffectedByFacilities FacilitiesComp => _facilitiesComp ?? (_facilitiesComp = parent.GetComp<CompAffectedByFacilities>());
public List<ProcessDef> Processes
{
get
{
if (_cachedProcesses == null)
{
BuildProcessList();
}
return _cachedProcesses;
}
}
public override void Initialize(CompProperties props) public override void Initialize(CompProperties props)
{ {
base.Initialize(props); base.Initialize(props);
_fuelComp = parent.GetComp<CompRefuelableNutrition>(); _fuelComp = parent.GetComp<CompRefuelableNutrition>();
_facilitiesComp = parent.GetComp<CompAffectedByFacilities>(); _facilitiesComp = parent.GetComp<CompAffectedByFacilities>();
BuildProcessList();
}
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
_fuelComp = parent.GetComp<CompRefuelableNutrition>();
_facilitiesComp = parent.GetComp<CompAffectedByFacilities>();
if (_cachedProcesses == null)
{
BuildProcessList();
}
} }
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn) public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
@@ -73,11 +102,11 @@ namespace ArachnaeSwarm
if (Props.whitelist == null || !Props.whitelist.Contains(selPawn.kindDef)) yield break; if (Props.whitelist == null || !Props.whitelist.Contains(selPawn.kindDef)) yield break;
if (FuelComp != null && (!FuelComp.HasFuel || FuelComp.NutritionStored < Props.minNutritionToStart)) if (FuelComp != null && (!FuelComp.HasFuel || FuelComp.NutritionStored < Props.minNutritionToStart))
{ {
yield return new FloatMenuOption("CannotStartProduction".Translate(), null); yield return new FloatMenuOption("CannotStartProduction".Translate() + ": " + "NoFuel".Translate(), null);
yield break; yield break;
} }
foreach (var process in Props.processes) foreach (var process in Processes)
{ {
if (process.requiredResearch != null && !process.requiredResearch.IsFinished) if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
{ {
@@ -85,7 +114,7 @@ namespace ArachnaeSwarm
} }
else else
{ {
yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () => yield return new FloatMenuOption("StartProduction".Translate(process.thingDef.label), () =>
{ {
this.selectedProcess = process; this.selectedProcess = process;
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_AddProcessToQueueJob"), parent); Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_AddProcessToQueueJob"), parent);
@@ -110,7 +139,6 @@ namespace ArachnaeSwarm
float ambientTemperature = parent.AmbientTemperature; float ambientTemperature = parent.AmbientTemperature;
bool isTempSafe = ambientTemperature >= Props.minSafeTemperature && ambientTemperature <= Props.maxSafeTemperature; bool isTempSafe = ambientTemperature >= Props.minSafeTemperature && ambientTemperature <= Props.maxSafeTemperature;
// Update progress and penalties for active orders
foreach(var order in producingOrders) foreach(var order in producingOrders)
{ {
if(hasFuel && isTempSafe) if(hasFuel && isTempSafe)
@@ -124,11 +152,10 @@ namespace ArachnaeSwarm
} }
if (!hasFuel) if (!hasFuel)
{ {
order.productionUntilTick++; // Pause production order.productionUntilTick++;
} }
} }
// Update fuel consumption
if (FuelComp != null) if (FuelComp != null)
{ {
float totalConsumptionRatePerDay = 0f; float totalConsumptionRatePerDay = 0f;
@@ -145,7 +172,6 @@ namespace ArachnaeSwarm
FuelComp.currentConsumptionRate = totalConsumptionRatePerDay; FuelComp.currentConsumptionRate = totalConsumptionRatePerDay;
} }
// Finish completed orders
productionOrders.RemoveAll(order => productionOrders.RemoveAll(order =>
{ {
if (order.productionUntilTick > 0 && Find.TickManager.TicksGame >= order.productionUntilTick) if (order.productionUntilTick > 0 && Find.TickManager.TicksGame >= order.productionUntilTick)
@@ -156,7 +182,6 @@ namespace ArachnaeSwarm
return false; return false;
}); });
// Start new orders
int currentlyProducingCount = productionOrders.Count(o => o.productionUntilTick > 0); int currentlyProducingCount = productionOrders.Count(o => o.productionUntilTick > 0);
if (currentlyProducingCount < Props.productionQueueLimit) if (currentlyProducingCount < Props.productionQueueLimit)
{ {
@@ -206,32 +231,37 @@ namespace ArachnaeSwarm
public override string CompInspectStringExtra() public override string CompInspectStringExtra()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int producingCount = productionOrders.Count(o => o.productionUntilTick > 0); int producingCount = productionOrders.Count(o => o.productionUntilTick > 0);
int queuedCount = productionOrders.Count - producingCount; int queuedCount = productionOrders.Count - producingCount;
sb.AppendLine($"生产槽位: {producingCount} / {Props.productionQueueLimit}"); sb.AppendLine($"生产槽位: {producingCount} / {Props.productionQueueLimit}");
if (queuedCount > 0) sb.AppendLine($"等待队列: {queuedCount}"); if (queuedCount > 0) sb.AppendLine($"等待队列: {queuedCount}");
if (FacilitiesComp != null) if (FacilitiesComp != null)
{ {
float speedFactor = 1f + FacilitiesComp.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")); float speedFactor = 1f + FacilitiesComp.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor"));
if(speedFactor != 1f) sb.AppendLine($"生产速度: {speedFactor.ToStringPercent()}"); if (speedFactor != 1f) sb.AppendLine($"生产速度: {speedFactor.ToStringPercent()}");
} }
var producingNow = productionOrders.Where(o => o.productionUntilTick > 0).OrderBy(o => o.productionUntilTick); var producingNow = productionOrders.Where(o => o.productionUntilTick > 0).OrderBy(o => o.productionUntilTick);
if (producingNow.Any()) if (producingNow.Any())
{ {
sb.AppendLine("正在生产:"); sb.AppendLine("正在生产:");
foreach (var order in producingNow) foreach (var order in producingNow)
{ {
if (order.process == null) continue;
int remainingTicks = order.productionUntilTick - Find.TickManager.TicksGame; int remainingTicks = order.productionUntilTick - Find.TickManager.TicksGame;
var qualityDetails = GetEstimatedQualityDetails(order); var qualityDetails = GetEstimatedQualityDetails(order);
sb.AppendLine($" - {order.process.thingDef.LabelCap}: {remainingTicks.ToStringTicksToPeriod(true, false, true, true)} (品质: {qualityDetails.quality.GetLabel()})"); sb.AppendLine($" - {order.process.thingDef.LabelCap}: {remainingTicks.ToStringTicksToPeriod(true, false, true, true)} (品质: {qualityDetails.quality.GetLabel()})");
} }
} }
else if (queuedCount == 0)
// 添加温度信息 {
int availableProcesses = Processes.Count(p => p.requiredResearch == null || p.requiredResearch.IsFinished);
sb.AppendLine("ARA_NeedArachnaeToStartIncubation".Translate() + $" ({availableProcesses} items available)");
}
string tempStr = "CurrentTemperature".Translate(parent.AmbientTemperature.ToStringTemperature("F0")); string tempStr = "CurrentTemperature".Translate(parent.AmbientTemperature.ToStringTemperature("F0"));
tempStr += $" ({"SafeTemperatureRange".Translate()}: {Props.minSafeTemperature.ToStringTemperature("F0")} ~ {Props.maxSafeTemperature.ToStringTemperature("F0")})"; tempStr += $" ({"SafeTemperatureRange".Translate()}: {Props.minSafeTemperature.ToStringTemperature("F0")} ~ {Props.maxSafeTemperature.ToStringTemperature("F0")})";
sb.AppendLine(tempStr); sb.AppendLine(tempStr);
@@ -242,8 +272,44 @@ namespace ArachnaeSwarm
public override void PostExposeData() public override void PostExposeData()
{ {
base.PostExposeData(); base.PostExposeData();
Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep); Scribe_Collections.Look(ref productionOrders, "productionOrders", LookMode.Deep, new object[0]);
Scribe_Deep.Look(ref selectedProcess, "selectedProcess");
ThingDef selectedProcessThingDef = selectedProcess?.thingDef;
Scribe_Defs.Look(ref selectedProcessThingDef, "selectedProcessThingDef");
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
var _ = Processes;
if (selectedProcessThingDef != null)
{
selectedProcess = _cachedProcesses.FirstOrDefault(p => p.thingDef == selectedProcessThingDef);
}
if (productionOrders == null)
{
productionOrders = new List<QueuedProcessOrder>();
}
productionOrders.RemoveAll(order =>
{
if (string.IsNullOrEmpty(order.tempThingDefName))
{
Log.Warning($"CompQueuedInteractiveProducer: Found a queued order with no thingDefName after loading. Removing it.");
return true;
}
order.process = _cachedProcesses.FirstOrDefault(p => p.thingDef.defName == order.tempThingDefName);
if (order.process == null)
{
Log.Warning($"CompQueuedInteractiveProducer: Could not find a matching ProcessDef for '{order.tempThingDefName}' after loading. The item may have been removed. Removing order.");
return true;
}
return false;
});
}
} }
public override IEnumerable<Gizmo> CompGetGizmosExtra() public override IEnumerable<Gizmo> CompGetGizmosExtra()
@@ -256,18 +322,101 @@ namespace ArachnaeSwarm
if (productionOrders.Any()) if (productionOrders.Any())
{ {
var lastOrder = productionOrders.Last(); var lastOrder = productionOrders.Last();
if(lastOrder.process != null)
yield return new Command_Action
{ {
defaultLabel = "CommandCancelProduction".Translate() + ": " + lastOrder.process.thingDef.LabelCap, yield return new Command_Action
defaultDesc = "CommandCancelProductionDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel"),
action = () =>
{ {
productionOrders.Remove(lastOrder); defaultLabel = "CommandCancelProduction".Translate() + ": " + lastOrder.process.thingDef.LabelCap,
} defaultDesc = "CommandCancelProductionDesc".Translate(),
}; icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel"),
action = () =>
{
productionOrders.Remove(lastOrder);
}
};
}
} }
} }
private void BuildProcessList()
{
_cachedProcesses = new List<ProcessDef>();
foreach (ThingDef thingDef in DefDatabase<ThingDef>.AllDefs)
{
if (thingDef.IsApparel || thingDef.IsWeapon)
{
var incubationCompProps = thingDef.GetCompProperties<CompProperties_ExtraIncubationInfo>();
if (incubationCompProps != null)
{
bool isMatch = false;
if (!incubationCompProps.cocoonDefs.NullOrEmpty())
{
isMatch = incubationCompProps.cocoonDefs.Contains(parent.def);
}
else if (incubationCompProps.cocoonDef != null)
{
isMatch = incubationCompProps.cocoonDef == parent.def;
}
if(isMatch)
{
ResearchProjectDef researchPrerequisite = null;
if (thingDef.recipeMaker?.researchPrerequisite != null)
{
researchPrerequisite = thingDef.recipeMaker.researchPrerequisite;
}
else if (thingDef.recipeMaker?.researchPrerequisites?.Count > 0)
{
researchPrerequisite = thingDef.recipeMaker.researchPrerequisites[0];
}
else if (thingDef.researchPrerequisites?.Count > 0)
{
researchPrerequisite = thingDef.researchPrerequisites[0];
}
ProcessDef process = new ProcessDef
{
thingDef = thingDef,
productionTicks = GetIncubationTimeTicks(thingDef),
totalNutritionNeeded = GetIncubationCost(thingDef),
requiredResearch = researchPrerequisite
};
_cachedProcesses.Add(process);
}
}
}
}
_cachedProcesses.SortBy(p => p.thingDef.label);
}
private int GetIncubationTimeTicks(ThingDef thingDef)
{
StatDef incubationTimeStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationTime");
if (incubationTimeStat != null && thingDef.statBases != null)
{
var statValue = thingDef.statBases.FirstOrDefault(s => s.stat == incubationTimeStat);
if (statValue != null)
{
return Mathf.RoundToInt(statValue.value * 60000f);
}
}
return 60000;
}
private float GetIncubationCost(ThingDef thingDef)
{
StatDef incubationCostStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationCost");
if (incubationCostStat != null && thingDef.statBases != null)
{
var statValue = thingDef.statBases.FirstOrDefault(s => s.stat == incubationCostStat);
if (statValue != null)
{
return statValue.value;
}
}
return 10f;
}
} }
} }

View File

@@ -1,4 +1,5 @@
using RimWorld; using RimWorld;
using System.Collections.Generic;
using Verse; using Verse;
namespace ArachnaeSwarm namespace ArachnaeSwarm
@@ -8,6 +9,6 @@ namespace ArachnaeSwarm
public CompProperties_ExtraIncubationInfo Props => (CompProperties_ExtraIncubationInfo)props; public CompProperties_ExtraIncubationInfo Props => (CompProperties_ExtraIncubationInfo)props;
// 公开属性,供其他组件读取 // 公开属性,供其他组件读取
public ThingDef CocoonDef => Props.cocoonDef; public List<ThingDef> CocoonDefs => Props.cocoonDefs;
} }
} }

View File

@@ -1,11 +1,15 @@
using RimWorld; using RimWorld;
using System.Collections.Generic;
using Verse; using Verse;
namespace ArachnaeSwarm namespace ArachnaeSwarm
{ {
public class CompProperties_ExtraIncubationInfo : CompProperties public class CompProperties_ExtraIncubationInfo : CompProperties
{ {
// 指定的茧建筑定义 // 指定的茧建筑定义列表 (新版)
public List<ThingDef> cocoonDefs;
// 为了向后兼容指定的单个建筑定义 (旧版)
public ThingDef cocoonDef; public ThingDef cocoonDef;
public CompProperties_ExtraIncubationInfo() public CompProperties_ExtraIncubationInfo()
{ {