diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index d56bfb1..164255d 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml index 05e370b..2856bc2 100644 --- a/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml +++ b/1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml @@ -293,7 +293,7 @@
  • ARA_NeuroSwarm_jump
  • ARA_GuardianPsyField_On
  • ARA_GuardianPsyField_Off
  • - +
  • ARA_Ability_Morph
  • diff --git a/1.6/1.6/Defs/Stats/ARA_Stats.xml b/1.6/1.6/Defs/Stats/ARA_Stats.xml index 7b818f6..abd7706 100644 --- a/1.6/1.6/Defs/Stats/ARA_Stats.xml +++ b/1.6/1.6/Defs/Stats/ARA_Stats.xml @@ -25,32 +25,36 @@ ARA_Incubation_StatCategory - 999 + 100 ARA_IncubationCost - 孵化该武装器官/织物所需的总营养 ARA_Incubation_StatCategory 1 0 - Integer - true + FloatOne + {0} 份 + 5010 - false + + true ARA_IncubationTime - 孵化该武装器官/织物所需的时间 ARA_Incubation_StatCategory 1 0 - Integer - true - 5010 - false + FloatOne + {0} 天 + + 5011 + + + true \ No newline at end of file diff --git a/1.6/1.6/Defs/Thing_Misc/Apparels/ARA_Apparel.xml b/1.6/1.6/Defs/Thing_Misc/Apparels/ARA_Apparel.xml index d597601..9d44699 100644 --- a/1.6/1.6/Defs/Thing_Misc/Apparels/ARA_Apparel.xml +++ b/1.6/1.6/Defs/Thing_Misc/Apparels/ARA_Apparel.xml @@ -18,7 +18,7 @@
  • ARA_Inner
  • -
  • Torso
  • +
  • Torso
  • OnSkin
  • @@ -35,9 +35,9 @@ - ARA_Bodystocking_White - - 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 + ARA_Bodystocking_White + + 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 ARA_Cocoon_Cloth @@ -54,12 +54,19 @@ 3000 + 1 + 1 + +
  • + ARA_Cocoon_Cloth +
  • +
    - ARA_Bodystocking_Black - - 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 + ARA_Bodystocking_Black + + 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 ARA_Cocoon_Cloth @@ -76,12 +83,19 @@ 3000 + 1 + 1 + +
  • + ARA_Cocoon_Cloth +
  • +
    - ARA_Latex_Catsuit - - 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 + ARA_Latex_Catsuit + + 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 ARA_Cocoon_Cloth @@ -98,12 +112,19 @@ 3000 + 1 + 1 + +
  • + ARA_Cocoon_Cloth +
  • +
    - ARA_Pantyhose_Black - - 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 + ARA_Pantyhose_Black + + 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 ARA_Cocoon_Cloth @@ -120,12 +141,19 @@ 3000 + 1 + 1 + +
  • + ARA_Cocoon_Cloth +
  • +
    - ARA_Pantyhose_White - - 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 + ARA_Pantyhose_White + + 阿拉克涅虫群的装饰性织物,对于虫群来说应该是没啥用的东西。 ARA_Cocoon_Cloth @@ -142,7 +170,14 @@ 3000 + 1 + 1 + +
  • + ARA_Cocoon_Cloth +
  • +
    @@ -223,9 +258,9 @@ - ARA_Maid_Uniform - - 阿拉克涅督虫们所着织物中的一种,设计上修身轻便,可以使其在阿拉克捏菌毯上获得额外的工作速度,是她们永远服侍虫巢的形象的完美具现化。 + ARA_Maid_Uniform + + 阿拉克涅督虫们所着织物中的一种,设计上修身轻便,可以使其在阿拉克捏菌毯上获得额外的工作速度,是她们永远服侍虫巢的形象的完美具现化。 ARA_Cocoon_Cloth @@ -242,10 +277,10 @@ -
  • Torso
  • -
  • Shoulders
  • -
  • Arms
  • -
  • Legs
  • +
  • Torso
  • +
  • Shoulders
  • +
  • Arms
  • +
  • Legs
  • @@ -255,17 +290,24 @@
    + + 10 + 2 + 0
  • ARA_TerrainWorkSpeedHediff
  • +
  • + ARA_Cocoon_Cloth +
  • - ARA_Bunny_Girl_Uniform - - 阿拉克涅督虫们所着织物中的一种,紧紧贴合督虫们的身体曲线,可以使其在阿拉克捏菌毯上获得额外的移动速度。 + ARA_Bunny_Girl_Uniform + + 阿拉克涅督虫们所着织物中的一种,紧紧贴合督虫们的身体曲线,可以使其在阿拉克捏菌毯上获得额外的移动速度。 ARA_Cocoon_Cloth_1Stage @@ -282,10 +324,10 @@ -
  • Torso
  • -
  • Shoulders
  • -
  • Arms
  • -
  • Legs
  • +
  • Torso
  • +
  • Shoulders
  • +
  • Arms
  • +
  • Legs
  • @@ -293,6 +335,10 @@ ArachnaeSwarm/Apparel/ARA_Bunny_Girl_Uniform
    + + 120 + 2.5 + 0 @@ -300,14 +346,17 @@
  • ARA_TerrainMoveSpeedHediff
  • +
  • + ARA_Cocoon_Cloth_1Stage +
  • - ARA_Nurse_Uniform - - 阿拉克涅督虫们所着织物中的一种,似乎是从人类的社会中得到了红十字元素的设计构思——只是虫群自己并不清楚为什么要使用这个标志。织物内部蕴含多根愈合素导管,可以让阿拉克涅虫族从菌毯中抽取营养以治疗其他个体。 + ARA_Nurse_Uniform + + 阿拉克涅督虫们所着织物中的一种,似乎是从人类的社会中得到了红十字元素的设计构思——只是虫群自己并不清楚为什么要使用这个标志。织物内部蕴含多根愈合素导管,可以让阿拉克涅虫族从菌毯中抽取营养以治疗其他个体。 - ARA_Cocoon_Cloth_2Stage + ARA_Cocoon_Cloth_1Stage ARA_TerrainHeal_Ability @@ -318,15 +367,19 @@ 25 + + 350 + 5 + ArachnaeSwarm/Apparel/ARA_Nurse_Uniform -
  • Torso
  • -
  • Shoulders
  • -
  • Arms
  • -
  • Legs
  • +
  • Torso
  • +
  • Shoulders
  • +
  • Arms
  • +
  • Legs
  • @@ -341,12 +394,15 @@
  • ARA_TerrainHealHediff
  • +
  • + ARA_Cocoon_Cloth_1Stage +
  • - ARA_Wedding_Dress - - 阿拉克涅督虫们所着织物中的一种,拥有摄人心魄的力量,可以抽取菌毯的力量发动夺取心智的能力,让敌方调转枪口攻击自己人。 + ARA_Wedding_Dress + + 阿拉克涅督虫们所着织物中的一种,拥有摄人心魄的力量,可以抽取菌毯的力量发动夺取心智的能力,让敌方调转枪口攻击自己人。 ARA_Cocoon_Cloth_2Stage ARA_TerrainTempt_Ability @@ -364,10 +420,10 @@ -
  • Torso
  • -
  • Shoulders
  • -
  • Arms
  • -
  • Legs
  • +
  • Torso
  • +
  • Shoulders
  • +
  • Arms
  • +
  • Legs
  • @@ -375,6 +431,10 @@ ArachnaeSwarm/Apparel/ARA_Wedding_Dress
    + + 350 + 5 + 0 @@ -382,12 +442,15 @@
  • ARA_TerrainTemptHediff
  • +
  • + ARA_Cocoon_Cloth_2Stage +
  • - ARA_Dragoon_Uniform - - 阿拉克涅虫群中的高阶战士所着织物,她们能够发出震耳欲聋的咆哮,并且看上去给人一种意外的庄严感——只不过她们挥着咔咔作响的鳌钳将你的同伴撕裂时,所有美好的幻想都会成为泡影。 + ARA_Dragoon_Uniform + + 阿拉克涅虫群中的高阶战士所着织物,她们能够发出震耳欲聋的咆哮,并且看上去给人一种意外的庄严感——只不过她们挥着咔咔作响的鳌钳将你的同伴撕裂时,所有美好的幻想都会成为泡影。 ARA_Cocoon_Cloth_2Stage ARA_TerrorRoar_Ability @@ -405,10 +468,10 @@ -
  • Torso
  • -
  • Shoulders
  • -
  • Arms
  • -
  • Legs
  • +
  • Torso
  • +
  • Shoulders
  • +
  • Arms
  • +
  • Legs
  • @@ -416,6 +479,10 @@ ArachnaeSwarm/Apparel/ARA_Dragoon_Uniform
    + + 500 + 10 + 0 @@ -423,12 +490,15 @@
  • ARA_TerrainTerrorRoar_Hediff
  • +
  • + ARA_Cocoon_Cloth_2Stage +
  • - - Shield - - 275 - + + Shield + + 275 + \ No newline at end of file diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml index 63f0a46..9ceca4d 100644 --- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml +++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml @@ -31,6 +31,8 @@ 1000 5 + 25 + 2.5
  • @@ -66,6 +68,11 @@
  • RewardStandardQualitySuper
  • + +
  • + ARA_Cocoon_Weapon +
  • +
    ARA_MW_Cartilage_Whip @@ -261,6 +268,8 @@ 0.45 0.3 1.25 + 15 + 1
  • @@ -307,6 +316,9 @@
  • +
  • + ARA_Cocoon_Weapon +
  • ARA_Weapon_Damage_Toxid
  • diff --git a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml index cb54cf1..0e8828c 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml @@ -515,6 +515,9 @@ ARA_Bodystocking_White ARA_Bodystocking_Black + ARA_Latex_Catsuit + ARA_Pantyhose_Black + ARA_Pantyhose_White ARA_Maid_Uniform @@ -535,25 +538,6 @@
  • - -
  • - ARA_Bodystocking_White - 6000 - 1 -
  • -
  • - ARA_Bodystocking_Black - 6000 - 1 -
  • -
  • - ARA_Maid_Uniform - 18000 - 15 - ARA_Technology_4DIL -
  • - -
  • ArachnaeNode_Race_WeaponSmith
  • @@ -633,26 +617,6 @@
  • - -
  • - ARA_MW_Bone_Sword - 60000 - 15 -
  • -
  • - ARA_RW_Basic_Fist_Needle_Gun - 40000 - 10 - ARA_Technology_5PAV -
  • -
  • - ARA_RW_Basic_Acid_Bladder_Gun - 80000 - 30 - ARA_Technology_7VXI -
  • - -
  • ArachnaeNode_Race_WeaponSmith
  • @@ -729,8 +693,8 @@
  • - - +
  • ArachnaeNode_Race_WeaponSmith
  • @@ -813,7 +777,7 @@
  • - +
  • ArachnaeNode_Race_WeaponSmith
  • @@ -916,8 +880,8 @@
  • - - +
  • ArachnaeNode_Race_WeaponSmith
  • @@ -999,7 +963,7 @@
  • - +
  • ArachnaeNode_Race_WeaponSmith
  • @@ -1104,7 +1068,7 @@
  • - +
  • ArachnaeNode_Race_Myrmecocystus
  • diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index cbd6a69..a89630e 100644 Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json index 2768895..ee53ed6 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -3,12 +3,8 @@ "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_destroyownbodypart\\compabilityeffect_destroyownbodypart.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_destroyownbodypart\\compabilityeffect_destroyownbodypart.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_destroyownbodypart\\compproperties_abilitydestroyownbodypart.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_destroyownbodypart\\compproperties_abilitydestroyownbodypart.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\stat\\statworker_incubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:stat\\statworker_incubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" } ], "DocumentGroupContainers": [ @@ -18,35 +14,23 @@ "DocumentGroups": [ { "DockedWidth": 200, - "SelectedChildIndex": 2, + "SelectedChildIndex": 1, "Children": [ { "$type": "Bookmark", "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" }, - { - "$type": "Document", - "DocumentIndex": 1, - "Title": "CompProperties_AbilityDestroyOwnBodyPart.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_DestroyOwnBodyPart\\CompProperties_AbilityDestroyOwnBodyPart.cs", - "RelativeDocumentMoniker": "Abilities\\ARA_DestroyOwnBodyPart\\CompProperties_AbilityDestroyOwnBodyPart.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_DestroyOwnBodyPart\\CompProperties_AbilityDestroyOwnBodyPart.cs", - "RelativeToolTip": "Abilities\\ARA_DestroyOwnBodyPart\\CompProperties_AbilityDestroyOwnBodyPart.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-09-28T08:57:43.206Z" - }, { "$type": "Document", "DocumentIndex": 0, - "Title": "CompAbilityEffect_DestroyOwnBodyPart.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_DestroyOwnBodyPart\\CompAbilityEffect_DestroyOwnBodyPart.cs", - "RelativeDocumentMoniker": "Abilities\\ARA_DestroyOwnBodyPart\\CompAbilityEffect_DestroyOwnBodyPart.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_DestroyOwnBodyPart\\CompAbilityEffect_DestroyOwnBodyPart.cs", - "RelativeToolTip": "Abilities\\ARA_DestroyOwnBodyPart\\CompAbilityEffect_DestroyOwnBodyPart.cs", - "ViewState": "AgIAADYAAAAAAAAAAAAIwGIAAAAJAAAAAAAAAA==", + "Title": "StatWorker_IncubationInfo.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Stat\\StatWorker_IncubationInfo.cs", + "RelativeDocumentMoniker": "Stat\\StatWorker_IncubationInfo.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Stat\\StatWorker_IncubationInfo.cs", + "RelativeToolTip": "Stat\\StatWorker_IncubationInfo.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-09-28T08:57:31.224Z", + "WhenOpened": "2025-09-30T08:38:06.014Z", "EditorCaption": "" } ] diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index eb83722..c491768 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -170,9 +170,12 @@ + + + diff --git a/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompInteractiveProducer.cs b/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompInteractiveProducer.cs index 1a21032..1dd2180 100644 --- a/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompInteractiveProducer.cs +++ b/Source/ArachnaeSwarm/Building_Comps/ARA_CompInteractiveProducer/CompInteractiveProducer.cs @@ -8,11 +8,9 @@ using Verse.AI; namespace ArachnaeSwarm { - // V14: Final refactor to work with the new GrowthVat-style fuel comp. - public class CompProperties_InteractiveProducer : CompProperties { - public List processes; + // 不再需要手动配置 processes 列表 public List whitelist; public IntRange spawnCount = new IntRange(1, 1); public bool destroyOnSpawn; @@ -21,7 +19,7 @@ namespace ArachnaeSwarm public float penaltyPerDegreePerTick = 0.00001f; public List qualityThresholds; public float damagePerTickWhenUnfueled = 0.2f; - public float minNutritionToStart = 0.1f; // Minimum fuel required to start a process + public float minNutritionToStart = 0.1f; public CompProperties_InteractiveProducer() { @@ -36,12 +34,27 @@ namespace ArachnaeSwarm private int productionUntilTick = -1; private int ticksUnderOptimalConditions; private float temperaturePenaltyPercent; + private List _cachedProcesses; private CompRefuelableNutrition _fuelComp; private static readonly Texture2D CancelIcon = ContentFinder.Get("UI/Designators/Cancel"); public bool InProduction => _selectedProcess != null; public CompProperties_InteractiveProducer Props => (CompProperties_InteractiveProducer)props; + + // 自动生成的 ProcessDef 列表 + public List Processes + { + get + { + if (_cachedProcesses == null) + { + BuildProcessList(); + } + return _cachedProcesses; + } + } + private CompRefuelableNutrition FuelComp { get @@ -55,12 +68,126 @@ namespace ArachnaeSwarm { base.PostSpawnSetup(respawningAfterLoad); _fuelComp = parent.GetComp(); + BuildProcessList(); // 确保进程列表在生成时构建 } public override void PostExposeData() { base.PostExposeData(); - // ... (Scribe logic is the same as V11) ... + + // 序列化 selectedProcess 的 thingDef 而不是整个 ProcessDef + ThingDef selectedProcessThingDef = _selectedProcess?.thingDef; + Scribe_Defs.Look(ref selectedProcessThingDef, "selectedProcessThingDef"); + + Scribe_Values.Look(ref productionUntilTick, "productionUntilTick", -1); + Scribe_Values.Look(ref ticksUnderOptimalConditions, "ticksUnderOptimalConditions", 0); + Scribe_Values.Look(ref temperaturePenaltyPercent, "temperaturePenaltyPercent", 0f); + + // 加载时重建 selectedProcess + if (Scribe.mode == LoadSaveMode.LoadingVars && selectedProcessThingDef != null) + { + // 确保 Processes 列表已构建 + if (_cachedProcesses == null) + { + BuildProcessList(); + } + + // 根据 thingDef 找到对应的 ProcessDef + _selectedProcess = Processes.FirstOrDefault(p => p.thingDef == selectedProcessThingDef); + + // 如果找不到对应的 ProcessDef,重置生产状态 + if (_selectedProcess == null) + { + Log.Warning($"Could not find ProcessDef for {selectedProcessThingDef.defName} after loading. Resetting production."); + ResetProduction(); + } + } + } + + // 自动构建 ProcessDef 列表的方法 + private void BuildProcessList() + { + _cachedProcesses = new List(); + + // 扫描所有定义了 CompExtraIncubationInfo 的物品 + foreach (ThingDef thingDef in DefDatabase.AllDefs) + { + // 检查是否是服装或武器 + if (thingDef.IsApparel || thingDef.IsWeapon) + { + var incubationCompProps = thingDef.GetCompProperties(); + if (incubationCompProps != null && incubationCompProps.cocoonDef == parent.def) + { + // 获取研究前提 - 从 recipeMaker 中获取 + ResearchProjectDef researchPrerequisite = null; + + // 方法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]; + } + + // 创建 ProcessDef + ProcessDef process = new ProcessDef + { + thingDef = thingDef, + productionTicks = GetIncubationTimeTicks(thingDef), + totalNutritionNeeded = GetIncubationCost(thingDef), + requiredResearch = researchPrerequisite + }; + + _cachedProcesses.Add(process); + } + } + } + + // 按物品名称排序以便更好的 UI 显示 + _cachedProcesses.SortBy(p => p.thingDef.label); + } + + // 获取孵化时间(转换为 ticks) + private int GetIncubationTimeTicks(ThingDef thingDef) + { + StatDef incubationTimeStat = DefDatabase.GetNamedSilentFail("ARA_IncubationTime"); + if (incubationTimeStat != null && thingDef.statBases != null) + { + var statValue = thingDef.statBases.FirstOrDefault(s => s.stat == incubationTimeStat); + if (statValue != null) + { + // ARA_IncubationTime 是以天为单位,转换为 ticks (1天 = 60000 ticks) + return Mathf.RoundToInt(statValue.value * 60000f); + } + } + + // 默认值:1 天 + return 60000; + } + + // 获取孵化所需营养 + private float GetIncubationCost(ThingDef thingDef) + { + StatDef incubationCostStat = DefDatabase.GetNamedSilentFail("ARA_IncubationCost"); + if (incubationCostStat != null && thingDef.statBases != null) + { + var statValue = thingDef.statBases.FirstOrDefault(s => s.stat == incubationCostStat); + if (statValue != null) + { + return statValue.value; + } + } + + // 默认值:10 营养 + return 10f; } public override void CompTick() @@ -70,8 +197,6 @@ namespace ArachnaeSwarm { if (FuelComp == null) return; - // Nutrition consumption is now handled by CompRefuelableNutrition's CompTick. - // We just need to check if there is any fuel left. bool hasFuel = FuelComp.HasFuel; if (!hasFuel) @@ -110,7 +235,8 @@ namespace ArachnaeSwarm yield break; } - foreach (var process in Props.processes) + // 使用自动生成的 Processes 列表 + foreach (var process in Processes) { if (process.requiredResearch != null && !process.requiredResearch.IsFinished) { @@ -135,7 +261,6 @@ namespace ArachnaeSwarm productionUntilTick = Find.TickManager.TicksGame + _selectedProcess.productionTicks; ticksUnderOptimalConditions = 0; temperaturePenaltyPercent = 0f; - // Set the consumption rate on the fuel comp (nutrition per day) float nutritionPerDay = (_selectedProcess.totalNutritionNeeded / _selectedProcess.productionTicks) * 60000f; FuelComp.currentConsumptionRate = nutritionPerDay; } @@ -144,25 +269,21 @@ namespace ArachnaeSwarm { if (!InProduction || Props.qualityThresholds.NullOrEmpty()) { - return (QualityCategory.Normal, 0f, 0f); // Default or no quality system + return (QualityCategory.Normal, 0f, 0f); } - // Estimate progress based on optimal ticks vs total ticks float progress = (float)ticksUnderOptimalConditions / _selectedProcess.productionTicks; - // Apply temperature penalty float finalQualityPercent = Mathf.Clamp01(progress - temperaturePenaltyPercent); QualityCategory finalQuality = QualityCategory.Awful; - // Find the best quality that meets the threshold foreach (var threshold in Props.qualityThresholds.OrderByDescending(q => q.threshold)) { if (finalQualityPercent >= threshold.threshold) { finalQuality = threshold.quality; - break; // Exit after finding the highest met quality + break; } } - // If no threshold is met, it will remain the lowest quality if (finalQuality == QualityCategory.Awful && Props.qualityThresholds.Any()) { finalQuality = Props.qualityThresholds.OrderBy(q => q.threshold).First().quality; @@ -179,27 +300,22 @@ namespace ArachnaeSwarm return; } - // 1. Determine final quality var qualityDetails = GetEstimatedQualityDetails(); QualityCategory finalQuality = qualityDetails.quality; - // 2. Create and spawn the item for (int i = 0; i < Props.spawnCount.RandomInRange; i++) { Thing product = ThingMaker.MakeThing(_selectedProcess.thingDef); product.TryGetComp()?.SetQuality(finalQuality, ArtGenerationContext.Colony); - // Spawn the item near the parent building GenPlace.TryPlaceThing(product, parent.Position, parent.Map, ThingPlaceMode.Near); } - // 3. Destroy self if configured if (Props.destroyOnSpawn) { parent.Destroy(DestroyMode.Vanish); } - // 4. Reset state ResetProduction(); } @@ -221,13 +337,11 @@ namespace ArachnaeSwarm int remainingTicks = productionUntilTick - Find.TickManager.TicksGame; sb.AppendLine("TimeLeft".Translate() + ": " + remainingTicks.ToStringTicksToPeriod()); - // Quality Details var qualityDetails = GetEstimatedQualityDetails(); sb.AppendLine("EstimatedQuality".Translate() + ": " + qualityDetails.quality.GetLabel()); sb.AppendLine($" {"QualityScore".Translate()}: {qualityDetails.baseScore.ToStringPercent("F0")}"); sb.AppendLine($" {"TemperaturePenalty".Translate()}: -{qualityDetails.penalty.ToStringPercent("F0")}"); - // Temperature Details string tempStr = "CurrentTemperature".Translate(parent.AmbientTemperature.ToStringTemperature("F0")); tempStr += $" ({"SafeTemperatureRange".Translate()}: {Props.minSafeTemperature.ToStringTemperature("F0")} ~ {Props.maxSafeTemperature.ToStringTemperature("F0")})"; sb.AppendLine(tempStr); @@ -236,7 +350,9 @@ namespace ArachnaeSwarm } if (!InProduction) { - return "ARA_NeedArachnaeToStartIncubation".Translate(); + // 显示可生产的物品数量 + int availableProcesses = Processes.Count(p => p.requiredResearch == null || p.requiredResearch.IsFinished); + return "ARA_NeedArachnaeToStartIncubation".Translate() + $" ({availableProcesses} items available)"; } return null; } @@ -255,4 +371,4 @@ namespace ArachnaeSwarm } } } -} \ No newline at end of file +} diff --git a/Source/ArachnaeSwarm/Stat/StatWorker_IncubationInfo.cs b/Source/ArachnaeSwarm/Stat/StatWorker_IncubationInfo.cs new file mode 100644 index 0000000..a7ac19d --- /dev/null +++ b/Source/ArachnaeSwarm/Stat/StatWorker_IncubationInfo.cs @@ -0,0 +1,172 @@ +using RimWorld; +using Verse; +using System.Linq; + +namespace ArachnaeSwarm +{ + // ARA_IncubationCost 的 StatWorker + public class StatWorker_IncubationCost : StatWorker + { + public override bool ShouldShowFor(StatRequest req) + { + try + { + // 只在拥有 CompProperties_ExtraIncubationInfo 的 ThingDef 上显示 + if (!base.ShouldShowFor(req)) + return false; + + return HasIncubationComp(req); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationCost.ShouldShowFor for {req.Def?.defName}: {ex.Message}"); + return false; + } + } + + public override float GetValueUnfinalized(StatRequest req, bool applyPostProcess = true) + { + try + { + // 从 ThingDef 的 statBases 中获取值 + if (req.Def is ThingDef thingDef) + { + var statModifier = thingDef.statBases?.FirstOrDefault(s => s.stat == this.stat); + if (statModifier != null) + { + return statModifier.value; + } + } + + return base.GetValueUnfinalized(req, applyPostProcess); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationCost.GetValueUnfinalized for {req.Def?.defName}: {ex.Message}"); + return 0f; + } + } + + public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) + { + try + { + if (!HasIncubationComp(req)) + return string.Empty; + + float value = GetValueUnfinalized(req); + return "IncubationCostDesc".Translate(value); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationCost.GetExplanationUnfinalized for {req.Def?.defName}: {ex.Message}"); + return string.Empty; + } + } + + private bool HasIncubationComp(StatRequest req) + { + try + { + ThingDef thingDef = req.Def as ThingDef ?? req.Thing?.def; + return thingDef?.comps?.Any(c => c is CompProperties_ExtraIncubationInfo) == true; + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationCost.HasIncubationComp for {req.Def?.defName}: {ex.Message}"); + return false; + } + } + } + + // ARA_IncubationTime 的 StatWorker + public class StatWorker_IncubationTime : StatWorker + { + public override bool ShouldShowFor(StatRequest req) + { + try + { + // 只在拥有 CompProperties_ExtraIncubationInfo 的 ThingDef 上显示 + if (!base.ShouldShowFor(req)) + return false; + + return HasIncubationComp(req); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationTime.ShouldShowFor for {req.Def?.defName}: {ex.Message}"); + return false; + } + } + + public override float GetValueUnfinalized(StatRequest req, bool applyPostProcess = true) + { + try + { + // 从 ThingDef 的 statBases 中获取值 + if (req.Def is ThingDef thingDef) + { + var statModifier = thingDef.statBases?.FirstOrDefault(s => s.stat == this.stat); + if (statModifier != null) + { + return statModifier.value; + } + } + + return base.GetValueUnfinalized(req, applyPostProcess); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationTime.GetValueUnfinalized for {req.Def?.defName}: {ex.Message}"); + return 0f; + } + } + + public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) + { + try + { + if (!HasIncubationComp(req)) + return string.Empty; + + float value = GetValueUnfinalized(req); + return "IncubationTimeDesc".Translate(value); + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationTime.GetExplanationUnfinalized for {req.Def?.defName}: {ex.Message}"); + return string.Empty; + } + } + + public override string GetStatDrawEntryLabel(StatDef stat, float value, ToStringNumberSense numberSense, StatRequest req, bool finalized = true) + { + try + { + if (!HasIncubationComp(req)) + return base.GetStatDrawEntryLabel(stat, value, numberSense, req, finalized); + + return value + " days"; + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationTime.GetStatDrawEntryLabel for {req.Def?.defName}: {ex.Message}"); + return value.ToString(); + } + } + + private bool HasIncubationComp(StatRequest req) + { + try + { + ThingDef thingDef = req.Def as ThingDef ?? req.Thing?.def; + return thingDef?.comps?.Any(c => c is CompProperties_ExtraIncubationInfo) == true; + } + catch (System.Exception ex) + { + Log.Warning($"Error in StatWorker_IncubationTime.HasIncubationComp for {req.Def?.defName}: {ex.Message}"); + return false; + } + } + } +} diff --git a/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompExtraIncubationInfo.cs b/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompExtraIncubationInfo.cs new file mode 100644 index 0000000..e89ef79 --- /dev/null +++ b/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompExtraIncubationInfo.cs @@ -0,0 +1,13 @@ +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public class CompExtraIncubationInfo : ThingComp + { + public CompProperties_ExtraIncubationInfo Props => (CompProperties_ExtraIncubationInfo)props; + + // 公开属性,供其他组件读取 + public ThingDef CocoonDef => Props.cocoonDef; + } +} diff --git a/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompProperties_ExtraIncubationInfo.cs b/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompProperties_ExtraIncubationInfo.cs new file mode 100644 index 0000000..9505232 --- /dev/null +++ b/Source/ArachnaeSwarm/Thing_Comps/ARA_CompExtraIncubationInfo/CompProperties_ExtraIncubationInfo.cs @@ -0,0 +1,15 @@ +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public class CompProperties_ExtraIncubationInfo : CompProperties + { + // 指定的茧建筑定义 + public ThingDef cocoonDef; + public CompProperties_ExtraIncubationInfo() + { + compClass = typeof(CompExtraIncubationInfo); + } + } +}