diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index a214cda7..eff3aecb 100644
Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ
diff --git a/1.6/1.6/Defs/ThingDefs_Races/WULA_Race_Mech_Warqueen_Example.xml b/1.6/1.6/Defs/ThingDefs_Races/WULA_Race_Mech_Warqueen_Example.xml
new file mode 100644
index 00000000..a34f2a8f
--- /dev/null
+++ b/1.6/1.6/Defs/ThingDefs_Races/WULA_Race_Mech_Warqueen_Example.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+ WULA_Mech_Warqueen
+ war queen (WULA)
+ An ultra-heavy mech with a built-in mech gestator. Fed with appropriate resources, the war queen can form small war urchin combat mechs within its massive carapace and deploy them into combat.\n\nEven more than other mechanoids, the war queen resembles a giant, living insect. All war mechs can be terrifying, but humans tend to find the war queen disturbing on a deeper level.
+
+ 1.6
+ 0.5
+ 3
+ 1.5
+ 0.7
+
+
+ Mech_Warqueen
+ 4
+
+
+ MechanoidFullyFormed
+ 0
+ Pawn_Mech_Warqueen_Wounded
+ Pawn_Mech_Warqueen_Death
+ Pawn_Mech_Warqueen_Call
+
+
+ MechanoidFullyFormed
+ 100
+ Pawn_Mech_Warqueen_Wounded
+ Pawn_Mech_Warqueen_Death
+ Pawn_Mech_Warqueen_Call
+
+
+ 5.2
+ Warqueen
+
+
+ ChunkMechanoidSlag
+ 13
+ 0.75
+
+
+ ChunkMechanoidSlag
+ 3
+ 0.75
+
+
+ ChunkMechanoidSlag
+ 0
+ 0.75
+
+
+
+
+
+ head
+
+ Blunt
+
+ 4
+ 2
+ HeadAttackTool
+ true
+ 0.2
+
+
+
+
+
+ true
+ true
+ 900
+
+
+ Mech_WarUrchin
+ 2
+
+
+ Mech_Lancer
+ 1
+
+
+ WarqueenWarUrchinsSpawned
+ WarUrchinSpawned
+
+
+ WULA_Penetrating_BeamTurret
+ -90
+ false
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ (1, 1)
+ Body
+ 20
+ Any
+
+
+ 180
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ WULA_Penetrating_BeamTurret
+ charge blaster turret
+ A small charge blaster designed for use on a defense turret.
+ None
+ true
+
+ Things/Item/Equipment/WeaponRanged/ChargeBlasterTurret
+ Graphic_Single
+
+
+ 2.6
+ 0.60
+ 0.80
+ 0.90
+ 0.85
+
+
+
+ Verb_Shoot
+ Bullet_WULA_RW_Penetrating_Beam_Ranged
+ 44.9
+ 30
+ Shot_ChargeBlaster
+ GunTail_Heavy
+ 9
+ 2.5
+ BulbTurret
+ true
+ 50
+
+
+
+
+
+ WULA_Mech_Warqueen
+ war queen (WULA)
+ war queens (WULA)
+ WULA_Mech_Warqueen
+ 600
+ 3
+ true
+ false
+
+
+
+ Things/Pawn/Mechanoid/Warqueen
+ Things/Pawn/Mechanoid/AllegianceOverlays/MechWarqueen
+ CutoutWithOverlay
+ Graphic_Multi
+ 3
+
+ (0.7, 0.8, 0.7)
+
+
+
+
+
+ Things/Pawn/Mechanoid/WarqueenAncient
+ Things/Pawn/Mechanoid/AllegianceOverlays/MechWarqueen
+ CutoutWithOverlay
+ Graphic_Multi
+ 3
+
+ (0.7, 0.8, 0.7)
+
+
+
+
+ 0.7
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified/Keyed/Misc_Gameplay.xml
new file mode 100644
index 00000000..03a2b5ee
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified/Keyed/Misc_Gameplay.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ 命令该单位生成 {0} 个 {1}。此操作不消耗任何资源。
+ 自动生产
+ 切换是否自动生产单位。开启后,当资源和冷却允许时,会自动生产单位以维持队列上限。
+ 自动生产已开启。再次点击以关闭。
+
+
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/CompAutoMechCarrier.cs b/Source/WulaFallenEmpire/CompAutoMechCarrier.cs
new file mode 100644
index 00000000..9e9a600a
--- /dev/null
+++ b/Source/WulaFallenEmpire/CompAutoMechCarrier.cs
@@ -0,0 +1,211 @@
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Verse;
+using Verse.AI.Group;
+
+namespace WulaFallenEmpire
+{
+ public class CompAutoMechCarrier : CompMechCarrier
+ {
+ private bool isAutoSpawning;
+
+ #region Reflected Fields
+ private static FieldInfo spawnedPawnsField;
+ private static FieldInfo cooldownTicksRemainingField;
+ private static FieldInfo innerContainerField;
+
+ private List SpawnedPawns
+ {
+ get
+ {
+ if (spawnedPawnsField == null)
+ spawnedPawnsField = typeof(CompMechCarrier).GetField("spawnedPawns", BindingFlags.NonPublic | BindingFlags.Instance);
+ return (List)spawnedPawnsField.GetValue(this);
+ }
+ }
+
+ private int CooldownTicksRemaining
+ {
+ get
+ {
+ if (cooldownTicksRemainingField == null)
+ cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
+ return (int)cooldownTicksRemainingField.GetValue(this);
+ }
+ set
+ {
+ if (cooldownTicksRemainingField == null)
+ cooldownTicksRemainingField = typeof(CompMechCarrier).GetField("cooldownTicksRemaining", BindingFlags.NonPublic | BindingFlags.Instance);
+ cooldownTicksRemainingField.SetValue(this, value);
+ }
+ }
+
+ private ThingOwner InnerContainer
+ {
+ get
+ {
+ if (innerContainerField == null)
+ innerContainerField = typeof(CompMechCarrier).GetField("innerContainer", BindingFlags.NonPublic | BindingFlags.Instance);
+ return (ThingOwner)innerContainerField.GetValue(this);
+ }
+ }
+ #endregion
+
+ public CompProperties_AutoMechCarrier AutoProps => (CompProperties_AutoMechCarrier)props;
+
+ private int TotalPawnCapacity => AutoProps.productionQueue.Sum(e => e.count);
+
+ private int LiveSpawnedPawnsCount(PawnKindDef kind)
+ {
+ SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
+ return SpawnedPawns.Count(p => p.kindDef == kind);
+ }
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+ if (!respawningAfterLoad)
+ {
+ isAutoSpawning = AutoProps.startsAsAutoSpawn;
+ }
+ }
+
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+ Scribe_Values.Look(ref isAutoSpawning, "isAutoSpawning", AutoProps.startsAsAutoSpawn);
+ }
+
+ private AcceptanceReport CanSpawnNow(PawnKindDef kind)
+ {
+ if (parent is Pawn pawn && (pawn.IsSelfShutdown() || !pawn.Awake() || pawn.Downed || pawn.Dead || !pawn.Spawned))
+ return false;
+ if (CooldownTicksRemaining > 0)
+ return "CooldownTime".Translate() + " " + CooldownTicksRemaining.ToStringSecondsFromTicks();
+ if (!AutoProps.freeProduction && InnerContainer.TotalStackCountOfDef(Props.fixedIngredient) < Props.costPerPawn)
+ return "MechCarrierNotEnoughResources".Translate();
+ return true;
+ }
+
+ private void TrySpawnPawn(PawnKindDef kind)
+ {
+ PawnGenerationRequest request = new PawnGenerationRequest(kind, parent.Faction, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: true);
+ Pawn pawn = PawnGenerator.GeneratePawn(request);
+ GenSpawn.Spawn(pawn, parent.Position, parent.Map);
+ SpawnedPawns.Add(pawn);
+
+ if (parent is Pawn p && p.GetLord() != null)
+ p.GetLord().AddPawn(pawn);
+
+ if (!AutoProps.freeProduction)
+ {
+ int costLeft = Props.costPerPawn;
+ List things = new List(InnerContainer);
+ for (int j = 0; j < things.Count; j++)
+ {
+ Thing thing = InnerContainer.Take(things[j], Mathf.Min(things[j].stackCount, costLeft));
+ costLeft -= thing.stackCount;
+ thing.Destroy();
+ if (costLeft <= 0) break;
+ }
+ }
+
+ CooldownTicksRemaining = Props.cooldownTicks;
+ if (Props.spawnedMechEffecter != null)
+ EffecterTrigger(Props.spawnedMechEffecter, Props.attachSpawnedMechEffecter, pawn);
+ if (Props.spawnEffecter != null)
+ EffecterTrigger(Props.spawnEffecter, Props.attachSpawnedEffecter, parent);
+ }
+
+ private void EffecterTrigger(EffecterDef effecterDef, bool attach, Thing target)
+ {
+ Effecter effecter = new Effecter(effecterDef);
+ effecter.Trigger(attach ? ((TargetInfo)target) : new TargetInfo(target.Position, target.Map), TargetInfo.Invalid);
+ effecter.Cleanup();
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+ if (isAutoSpawning && parent.IsHashIntervalTick(60)) // 每秒检查一次
+ {
+ if (CooldownTicksRemaining > 0) return;
+
+ foreach (var entry in AutoProps.productionQueue)
+ {
+ if (LiveSpawnedPawnsCount(entry.pawnKind) < entry.count)
+ {
+ if (CanSpawnNow(entry.pawnKind).Accepted)
+ {
+ TrySpawnPawn(entry.pawnKind);
+ break; // 每次只生产一个,然后等待下一次冷却
+ }
+ }
+ }
+ }
+ }
+
+ public override IEnumerable CompGetGizmosExtra()
+ {
+ // 拦截并改造基类的Gizmo
+ foreach (var gizmo in base.CompGetGizmosExtra())
+ {
+ // 通过图标来稳定地识别目标按钮
+ if (gizmo is Command_ActionWithCooldown command && command.icon == ContentFinder.Get("UI/Gizmos/ReleaseWarUrchins"))
+ {
+ // 我们只改造这个按钮,其他按钮原样返回
+ var modifiedCommand = new Command_ActionWithCooldown
+ {
+ // 保留冷却进度条的逻辑
+ cooldownPercentGetter = command.cooldownPercentGetter,
+ // 保留原版图标
+ icon = command.icon,
+ // 修改功能为切换自动生产
+ action = () => { isAutoSpawning = !isAutoSpawning; },
+ // 修改标签和描述
+ defaultLabel = "WULA_AutoSpawn_Label".Translate(),
+ defaultDesc = "WULA_AutoSpawn_Desc".Translate()
+ };
+
+ // 如果自动生产开启,则禁用按钮并显示红叉
+ if (isAutoSpawning)
+ {
+ modifiedCommand.Disable("WULA_AutoSpawn_On_Reason".Translate());
+ }
+
+ yield return modifiedCommand;
+ }
+ else
+ {
+ // 其他按钮(如开发者按钮)原样返回
+ yield return gizmo;
+ }
+ }
+ }
+
+ public override string CompInspectStringExtra()
+ {
+ SpawnedPawns.RemoveAll(p => p == null || p.Destroyed);
+ string text = "Pawns: " + SpawnedPawns.Count + " / " + TotalPawnCapacity;
+
+ foreach (var entry in AutoProps.productionQueue)
+ {
+ text += $"\n- {entry.pawnKind.LabelCap}: {LiveSpawnedPawnsCount(entry.pawnKind)} / {entry.count}";
+ }
+
+ if (CooldownTicksRemaining > 0)
+ {
+ text += "\n" + "CooldownTime".Translate() + ": " + CooldownTicksRemaining.ToStringSecondsFromTicks();
+ }
+
+ if (!AutoProps.freeProduction)
+ {
+ text += "\n" + base.CompInspectStringExtra();
+ }
+ return text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/CompProperties_AutoMechCarrier.cs b/Source/WulaFallenEmpire/CompProperties_AutoMechCarrier.cs
new file mode 100644
index 00000000..6ba1a6d6
--- /dev/null
+++ b/Source/WulaFallenEmpire/CompProperties_AutoMechCarrier.cs
@@ -0,0 +1,54 @@
+using RimWorld;
+using Verse;
+using System.Collections.Generic;
+
+namespace WulaFallenEmpire
+{
+ public class CompProperties_AutoMechCarrier : CompProperties_MechCarrier
+ {
+ // XML中定义,初始是否为自动生产模式
+ public bool startsAsAutoSpawn = false;
+
+ // XML中定义,生产是否消耗资源
+ public bool freeProduction = false;
+
+ // 定义生产队列
+ public List productionQueue = new List();
+
+ public CompProperties_AutoMechCarrier()
+ {
+ // 确保这个属性类指向我们新的功能实现类
+ compClass = typeof(CompAutoMechCarrier);
+ }
+
+ public override IEnumerable ConfigErrors(ThingDef parentDef)
+ {
+ foreach (string error in base.ConfigErrors(parentDef))
+ {
+ yield return error;
+ }
+
+ if (productionQueue.NullOrEmpty())
+ {
+ yield return "CompProperties_AutoMechCarrier must have at least one entry in productionQueue.";
+ }
+ }
+
+ public override void ResolveReferences(ThingDef parentDef)
+ {
+ base.ResolveReferences(parentDef);
+ // Prevent division by zero if costPerPawn is not set, which the base game AI might try to access.
+ if (costPerPawn <= 0)
+ {
+ costPerPawn = 1;
+ }
+
+ // 如果spawnPawnKind为空(因为我们用了新的队列系统),
+ // 就从队列里取第一个作为“假”值,以防止基类方法在生成Gizmo标签时出错。
+ if (spawnPawnKind == null && !productionQueue.NullOrEmpty())
+ {
+ spawnPawnKind = productionQueue[0].pawnKind;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/PawnProductionEntry.cs b/Source/WulaFallenEmpire/PawnProductionEntry.cs
new file mode 100644
index 00000000..4978648f
--- /dev/null
+++ b/Source/WulaFallenEmpire/PawnProductionEntry.cs
@@ -0,0 +1,17 @@
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ ///
+ /// A data class to hold information about a pawn to be produced in a queue.
+ /// Used in XML definitions.
+ ///
+ public class PawnProductionEntry
+ {
+ // The PawnKindDef of the unit to spawn.
+ public PawnKindDef pawnKind;
+
+ // The maximum number of this kind of unit to maintain.
+ public int count = 1;
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/StartupLogger.cs b/Source/WulaFallenEmpire/StartupLogger.cs
deleted file mode 100644
index 371f28fb..00000000
--- a/Source/WulaFallenEmpire/StartupLogger.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Verse;
-
-namespace WulaFallenEmpire
-{
- [StaticConstructorOnStartup]
- public static class StartupLogger
- {
- static StartupLogger()
- {
- Log.Message("WulaFallenEmpire Mod DLL, version 1.0.2, has been loaded.");
- }
- }
-}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index fa7ccff1..0e11552b 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -70,6 +70,9 @@
+
+
+
@@ -154,7 +157,6 @@
-
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpireMod.cs b/Source/WulaFallenEmpire/WulaFallenEmpireMod.cs
index a7d7479d..3a41b8fe 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpireMod.cs
+++ b/Source/WulaFallenEmpire/WulaFallenEmpireMod.cs
@@ -19,4 +19,13 @@ namespace WulaFallenEmpire
}
}
+
+ [StaticConstructorOnStartup]
+ public static class StartupLogger
+ {
+ static StartupLogger()
+ {
+ Log.Message("WulaFallenEmpire Mod DLL, version 1.0.2, has been loaded.");
+ }
+ }
}