diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index c572fd43..bf2a7b1b 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/PawnKinds/PawnKinds_Wula.xml b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml index 99da6873..0468f03e 100644 --- a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml +++ b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml @@ -305,10 +305,7 @@ 99999~99999 - 0.7 - -
  • Wula_Mech_Mobile_Factory_Main_Weapon
  • -
    + 0.7
  • Wula_Mech_Mobile_Factory_Produce
  • diff --git a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml index 72a6152a..516dbc1b 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml @@ -120,7 +120,7 @@ 0 5 true - 180 + 3
  • @@ -149,8 +149,8 @@
  • 36000 - 5.2 - 5.4 + 8.2 + 8.4 0.02 4.0 false @@ -165,22 +165,6 @@ WULA_Hover_FlyEast WULA_Hover_FlySouth
  • -
  • - 1.5 - 30 - Crush - 3 - false - false - false - true - false - false - false - 碾压伤害 - HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。 - Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage -
  • 1 @@ -403,7 +387,7 @@ 30 8 true - 180 + 3 @@ -441,22 +425,6 @@ WULA_Hover_FlyEast WULA_Hover_FlySouth
  • -
  • - 1.5 - 30 - Crush - 3 - false - false - false - true - false - false - false - 碾压伤害 - HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。 - Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage -
  • 1 @@ -580,6 +548,49 @@
  • --> + +
  • + + 1.0 + 2.0 + 15 + 3 + + + 3 + + + true + true + + + Blunt + 1 + 0.1 + + + MeleeHit_BladelinkZeusHammer + + + Blunt + 15 + 4 + true + + MeleeHit_BladelinkZeusHammer + + + PawnFlyer + + PawnFlyerLand + + + false + false + false +
  • @@ -1104,22 +1115,6 @@ WULA_Hover_FlyEast WULA_Hover_FlySouth -
  • - 3.5 - 30 - Crush - 4 - false - false - false - true - false - false - false - 碾压伤害 - MFm-2"陆行舰"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。 - Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage -
  • 1 diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml index 11717f91..ea2deecf 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml @@ -258,4 +258,11 @@ 该构装体仍有行动能力 {0} 撬开了 {1},里面仍活着的 {2} 个驾驶员冲出来了! {0} 撬开了 {1},并接管了它。 + + 按下以切换此炮塔系统的开关。 + 已清除集火目标 + 集中攻击 + 命令该单位所有的炮塔攻击指定目标。如果目标不处于某个炮塔的攻击范围或者无法攻击到目标,则其依然会自行索敌。 + 清除目标 + 清除指定的集中攻击目标,各炮塔将自行索敌。 diff --git a/Source/WulaFallenEmpire/HarmonyPatches/Patch_CaravanUIUtility_AddPawnsSections_Postfix.cs b/Source/WulaFallenEmpire/HarmonyPatches/Patch_CaravanUIUtility_AddPawnsSections_Postfix.cs index 064e2542..d148cd73 100644 --- a/Source/WulaFallenEmpire/HarmonyPatches/Patch_CaravanUIUtility_AddPawnsSections_Postfix.cs +++ b/Source/WulaFallenEmpire/HarmonyPatches/Patch_CaravanUIUtility_AddPawnsSections_Postfix.cs @@ -28,6 +28,22 @@ namespace WulaFallenEmpire widget.AddSection("WULA_AutonomousMechsSection".Translate(), autonomousMechs); WulaLog.Debug($"[WULA] Postfix: Added 'Autonomous Mechs' section with {autonomousMechs.Count} mechs."); } + + // 筛选出所有构装体 + var WulaMechunits = transferables + .Where(x => { + if (x.ThingDef.category != ThingCategory.Pawn) return false; + var pawn = x.AnyThing as Pawn; + return pawn != null && pawn is Wulamechunit; + }) + .ToList(); + + // 如果找到了任何构装体,就为它们添加一个新的分组 + if (WulaMechunits.Any()) + { + widget.AddSection("WULA_MechunitsSection".Translate(), WulaMechunits); + WulaLog.Debug($"[WULA] Postfix: Added 'Mechunits' section with {autonomousMechs.Count}."); + } } } } \ No newline at end of file diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_Pawn_RotationTracker_UpdateRotation.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_Pawn_RotationTracker_UpdateRotation.cs new file mode 100644 index 00000000..1fef68e6 --- /dev/null +++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_Pawn_RotationTracker_UpdateRotation.cs @@ -0,0 +1,79 @@ +using HarmonyLib; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using Verse; +namespace WulaFallenEmpire.HarmonyPatches +{ + [HarmonyPatch(typeof(Pawn_RotationTracker))] + [HarmonyPatch("UpdateRotation")] + public static class Patch_Pawn_RotationTracker_UpdateRotation + { + [HarmonyTranspiler] + public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator il) + { + var codes = new List(instructions); + + // 查找 pawn.Drafted 检查并修改 + for (int i = 0; i < codes.Count; i++) + { + // 查找加载 pawn 并调用 get_Drafted 的代码 + if (codes[i].opcode == OpCodes.Ldarg_0 && + i + 1 < codes.Count && codes[i + 1].opcode == OpCodes.Ldfld && + codes[i + 1].operand is FieldInfo field && field.Name == "pawn" && + i + 2 < codes.Count && codes[i + 2].opcode == OpCodes.Callvirt) + { + // 检查是否是 get_Drafted 方法 + var method = codes[i + 2].operand as MethodInfo; + if (method != null && method.Name == "get_Drafted") + { + // 查找随后的条件跳转 + for (int j = i + 3; j < codes.Count; j++) + { + if (codes[j].opcode == OpCodes.Brfalse || codes[j].opcode == OpCodes.Brfalse_S) + { + // 找到条件跳转,创建新标签用于额外检查 + var originalLabel = (Label)codes[j].operand; + var afterCheckLabel = il.DefineLabel(); + + // 修改原始跳转目标 + codes[j].operand = afterCheckLabel; + + // 在跳转指令后插入检查代码 + var insertCodes = new List + { + // 加载 pawn + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, + typeof(Pawn_RotationTracker).GetField("pawn", + BindingFlags.NonPublic | BindingFlags.Instance)), + + // 检查是否是 Wulamechunit + new CodeInstruction(OpCodes.Isinst, typeof(Wulamechunit)), + + // 如果是 Wulamechunit,跳转到原始标签(跳过设置 Rotation) + new CodeInstruction(OpCodes.Brtrue, originalLabel) + }; + + // 标记 afterCheckLabel + var labelCode = new CodeInstruction(OpCodes.Nop); + labelCode.labels.Add(afterCheckLabel); + insertCodes.Insert(0, labelCode); + + // 插入代码 + codes.InsertRange(j + 1, insertCodes); + + return codes; + } + } + } + } + } + + Log.Warning("[WulaFallenEmpire] Failed to find pawn.Drafted check in UpdateRotation"); + return codes; + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs b/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs index 2bf7f58e..69d4860e 100644 --- a/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs +++ b/Source/WulaFallenEmpire/Pawn_Comps/MultiTurretGun/CompMultiTurretGun.cs @@ -15,7 +15,12 @@ namespace WulaFallenEmpire public float idleRotationSpeed = 5f; // 空闲时的旋转速度(度/秒) public bool smoothRotation = true; // 是否启用平滑旋转 public float minAimAngle = 10f; // 开始预热所需的最小瞄准角度差(度) - public int resetCooldownTicks = 120; // 开火后的复位冷却时间(默认2秒) + public float resetCooldownTime = 3f; // 复位冷却时间(秒) + + // Gizmo 相关属性 + public string gizmoLabel; // Gizmo 标签 + public string gizmoDescription; // Gizmo 描述 + public string gizmoIconPath = "UI/Gizmos/ToggleTurret"; // Gizmo 图标路径 public CompProperties_MultiTurretGun() { @@ -35,24 +40,50 @@ namespace WulaFallenEmpire private bool isAiming = false; // 是否正在瞄准 private float lastBaseRotationAngle; // 上一次记录的基座角度 private float lastTargetAngle; // 最后一次目标角度 + private int resetCooldownTicksLeft = 0; // 复位冷却剩余tick数 + private bool isInResetCooldown = false; // 是否处于复位冷却中 // 添加缺失的字段 private LocalTargetInfo lastAttackedTarget = LocalTargetInfo.Invalid; private int lastAttackTargetTick; - // Gizmo相关静态字段 - private static readonly CachedTexture ToggleTurretIcon = new CachedTexture("UI/Gizmos/ToggleTurret"); - private static bool gizmoAdded = false; // 防止重复添加Gizmo + // 集中火力目标 + private static LocalTargetInfo focusTarget = LocalTargetInfo.Invalid; + private static int lastFocusSetTick = 0; + private static Thing lastFocusPawn = null; - // 复位冷却相关 - private int resetCooldownTicksLeft = 0; - private bool isInResetCooldown = false; + // Gizmo 缓存 + private Command_Toggle cachedGizmo; + private Command_Action cachedFocusGizmo; + private bool gizmoInitialized = false; public new CompProperties_MultiTurretGun Props => (CompProperties_MultiTurretGun)props; // 添加属性 private bool WarmingUp => burstWarmupTicksLeft > 0; + // 公开 fireAtWill 属性的访问器 + public bool FireAtWill + { + get => fireAtWill; + set + { + if (fireAtWill != value) + { + fireAtWill = value; + + // 如果关闭炮塔,重置当前目标 + if (!fireAtWill) + { + ResetCurrentTarget(); + } + } + } + } + + // 是否为ID=0的主控组件 + private bool IsMasterTurret => Props.ID == 0; + public override void Initialize(CompProperties props) { base.Initialize(props); @@ -73,7 +104,8 @@ namespace WulaFallenEmpire lastBaseRotationAngle = parent.Rotation.AsAngle; lastTargetAngle = currentRotationAngle; } - gizmoAdded = false; // 重置Gizmo状态 + // 重置 Gizmo 缓存 + gizmoInitialized = false; } private bool CanShoot @@ -94,7 +126,7 @@ namespace WulaFallenEmpire { return false; } - if (pawn.IsColonyMechPlayerControlled && !fireAtWill) + if (!fireAtWill) { return false; } @@ -104,6 +136,11 @@ namespace WulaFallenEmpire { return false; } + CompMechPilotHolder compMechPilotHolder = parent.TryGetComp(); + if (compMechPilotHolder != null && !compMechPilotHolder.HasPilots) + { + return false; + } return true; } } @@ -148,9 +185,11 @@ namespace WulaFallenEmpire lastAttackTargetTick = Find.TickManager.TicksGame; lastAttackedTarget = currentTarget; - // 开火后重置目标,并启动复位冷却 - ResetCurrentTarget(); + // 开火后开始复位冷却 StartResetCooldown(); + + // 开火后重置目标,等待冷却结束 + currentTarget = LocalTargetInfo.Invalid; } else { @@ -173,34 +212,45 @@ namespace WulaFallenEmpire burstCooldownTicksLeft--; } - // 冷却结束且复位冷却结束,尝试寻找目标 + // 冷却结束,尝试寻找目标(但不在复位冷却中时) if (burstCooldownTicksLeft <= 0 && !isInResetCooldown && parent.IsHashIntervalTick(10)) { TryAcquireTarget(); } - // 更新空闲旋转 - UpdateIdleRotation(); + // 检查是否已经瞄准目标但还没有开始预热 + // 这是关键修复:当炮塔已经瞄准目标但burstWarmupTicksLeft为0时,开始预热 + if (currentTarget.IsValid && IsAimedAtTarget() && burstWarmupTicksLeft <= 0 && burstCooldownTicksLeft <= 0 && !isInResetCooldown) + { + burstWarmupTicksLeft = Mathf.Max(1, Mathf.RoundToInt(Props.aimTicks)); + return; + } + + // 更新空闲旋转(只在复位冷却结束后) + if (!isInResetCooldown) + { + UpdateIdleRotation(); + } } private void UpdateResetCooldown() { - if (isInResetCooldown && resetCooldownTicksLeft > 0) + if (isInResetCooldown) { resetCooldownTicksLeft--; if (resetCooldownTicksLeft <= 0) { isInResetCooldown = false; - resetCooldownTicksLeft = 0; } } } private void StartResetCooldown() { - resetCooldownTicksLeft = Props.resetCooldownTicks; + // 计算复位冷却的tick数(秒转tick) + int resetCooldownTicks = Mathf.RoundToInt(Props.resetCooldownTime * 60f); + resetCooldownTicksLeft = Mathf.Max(1, resetCooldownTicks); isInResetCooldown = true; - ticksWithoutTarget = 0; // 重置无目标计数 } private void CheckPawnRotationChange() @@ -231,11 +281,35 @@ namespace WulaFallenEmpire private void TryAcquireTarget() { - // 如果正在复位冷却中,不寻找目标 - if (isInResetCooldown) - return; - - // 尝试寻找新目标 + // 1. 首先检查是否有集中火力目标且可以对其开火 + if (focusTarget.IsValid && focusTarget.Thing != null && focusTarget.Thing.Spawned) + { + // 检查是否属于同一个Pawn且在同一张地图 + if (lastFocusPawn == parent && focusTarget.Thing.Map == parent.Map) + { + // 检查能否看到目标 + if (CanSeeTarget(focusTarget.Thing)) + { + // 检查是否在射程内 + float distance = (focusTarget.CenterVector3 - parent.DrawPos).MagnitudeHorizontal(); + float maxRange = AttackVerb.verbProps.range; + + if (distance <= maxRange) + { + // 优先目标有效,将其作为目标 + SetCurrentTarget(focusTarget); + return; + } + } + } + else + { + // 不属于同一个Pawn或不在同一地图,清除集中火力目标 + focusTarget = LocalTargetInfo.Invalid; + } + } + + // 2. 如果没有有效的集中火力目标,执行原有索敌逻辑 LocalTargetInfo newTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition( this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable @@ -243,50 +317,69 @@ namespace WulaFallenEmpire if (newTarget.IsValid) { + // 如果有目标,立即结束复位冷却 + isInResetCooldown = false; + resetCooldownTicksLeft = 0; + // 如果已经有目标并且是同一个目标,保持当前状态 if (currentTarget.IsValid && currentTarget.Thing == newTarget.Thing) { - // 检查是否已经瞄准目标 - if (IsAimedAtTarget()) + // 检查是否已经瞄准目标但还没有开始预热 + // 关键修复:确保当炮塔已经瞄准目标时开始预热 + if (IsAimedAtTarget() && burstWarmupTicksLeft <= 0) { - // 如果已经瞄准,开始预热 - if (burstWarmupTicksLeft <= 0) - { - burstWarmupTicksLeft = Mathf.Max(1, Mathf.RoundToInt(Props.aimTicks)); - } - } - else if (IsAimingAtTarget()) - { - // 如果正在瞄准但未完成,保持当前状态 - // 什么也不做,继续旋转 - } - else - { - // 需要重新瞄准 - burstWarmupTicksLeft = 0; + burstWarmupTicksLeft = Mathf.Max(1, Mathf.RoundToInt(Props.aimTicks)); } } else { // 新目标,重置状态 - currentTarget = newTarget; - burstWarmupTicksLeft = 0; - isAiming = true; - - // 计算目标角度 - Vector3 targetPos = currentTarget.CenterVector3; - Vector3 turretPos = parent.DrawPos; - targetRotationAngle = (targetPos - turretPos).AngleFlat(); - lastTargetAngle = targetRotationAngle; + SetCurrentTarget(newTarget); } } else { - // 没有目标 - ResetCurrentTarget(); + // 没有目标,但如果在复位冷却中,不立即复位 + if (!isInResetCooldown) + { + ResetCurrentTarget(); + } + // 如果在复位冷却中,保持当前状态,等待冷却结束 } } + private bool CanSeeTarget(Thing target) + { + // 简单的视线检查,可以替换为更复杂的逻辑 + if (target == null || !target.Spawned) + return false; + + // 检查是否有障碍物遮挡 + if (!GenSight.LineOfSight(parent.Position, target.Position, parent.Map, skipFirstCell: true)) + { + return false; + } + + return true; + } + + private void SetCurrentTarget(LocalTargetInfo newTarget) + { + currentTarget = newTarget; + burstWarmupTicksLeft = 0; + isAiming = true; + + // 计算目标角度 + Vector3 targetPos = currentTarget.CenterVector3; + Vector3 turretPos = parent.DrawPos; + targetRotationAngle = (targetPos - turretPos).AngleFlat(); + lastTargetAngle = targetRotationAngle; + + // 重要:立即结束复位冷却,因为有了新目标 + isInResetCooldown = false; + resetCooldownTicksLeft = 0; + } + private bool IsAimingAtTarget() { if (!currentTarget.IsValid) @@ -342,10 +435,19 @@ namespace WulaFallenEmpire } else { - // 没有目标时,朝向初始角度 - targetRotationAngle = parent.Rotation.AsAngle + Props.angleOffset; - ticksWithoutTarget++; - lastTargetAngle = targetRotationAngle; + // 没有目标时,只有在复位冷却结束后才朝向初始角度 + if (!isInResetCooldown) + { + targetRotationAngle = parent.Rotation.AsAngle + Props.angleOffset; + ticksWithoutTarget++; + lastTargetAngle = targetRotationAngle; + } + else + { + // 在复位冷却中,保持当前角度不改变 + // 不更新targetRotationAngle,炮塔保持当前方向 + ticksWithoutTarget++; + } } // 确保角度在0-360范围内 @@ -407,7 +509,7 @@ namespace WulaFallenEmpire private void UpdateIdleRotation() { - // 只在没有目标、冷却结束且复位冷却结束时执行空闲旋转 + // 只在没有目标、冷却结束、并且复位冷却结束后执行空闲旋转 if (!currentTarget.IsValid && burstCooldownTicksLeft <= 0 && !isInResetCooldown && ticksWithoutTarget > 120) { if (!isIdleRotating) @@ -456,6 +558,12 @@ namespace WulaFallenEmpire { DrawTargetingLine(); } + + // 如果当前目标是集中火力目标,用特殊颜色绘制瞄准线 + if (currentTarget.IsValid && currentTarget.Thing == focusTarget.Thing) + { + DrawFocusTargetingLine(); + } } private void DrawTargetingLine() @@ -474,9 +582,23 @@ namespace WulaFallenEmpire Color lineColor = Color.Lerp(Color.yellow, Color.red, aimAccuracy); lineColor.a = 0.7f; - GenDraw.DrawLineBetween(lineStart, lineEnd); + GenDraw.DrawLineBetween(lineStart, lineEnd, SimpleColor.White); } + private void DrawFocusTargetingLine() + { + Vector3 lineStart = parent.DrawPos; + lineStart.y = AltitudeLayer.MetaOverlays.AltitudeFor(); + + Vector3 lineEnd = currentTarget.CenterVector3; + lineEnd.y = AltitudeLayer.MetaOverlays.AltitudeFor(); + + // 集中火力目标的特殊颜色 + Color lineColor = new Color(1f, 0.5f, 0f, 0.8f); // 橙色 + + // 绘制更粗的线条 + GenDraw.DrawLineBetween(lineStart, lineEnd); + } private void MakeGun() { @@ -498,7 +620,7 @@ namespace WulaFallenEmpire } } - // 添加Gizmo方法 + // 重构后的 Gizmo 方法 - 每个组件独立控制 public override IEnumerable CompGetGizmosExtra() { foreach (Gizmo gizmo in base.CompGetGizmosExtra()) @@ -506,71 +628,163 @@ namespace WulaFallenEmpire yield return gizmo; } - // 只让第一个Comp_MultiTurretGun组件生成Gizmo - if (parent is Pawn pawn && pawn.IsColonyMechPlayerControlled) + // 只对殖民地玩家控制的单位显示 Gizmo + if (parent is Pawn pawn && pawn.Faction.IsPlayer) { - // 获取所有Comp_MultiTurretGun组件 - var allTurretComps = parent.GetComps(); - - // 检查当前组件是否是第一个 - if (!gizmoAdded) + // 延迟初始化 Gizmo,只在需要时创建 + if (!gizmoInitialized) { - gizmoAdded = true; - - // 检查所有炮塔是否都有相同的fireAtWill状态 - bool allTurretsEnabled = true; - bool allTurretsDisabled = true; - - foreach (var turretComp in allTurretComps) - { - if (turretComp.fireAtWill) - allTurretsDisabled = false; - else - allTurretsEnabled = false; - } - - // 确定Gizmo的初始状态 - bool mixedState = !(allTurretsEnabled || allTurretsDisabled); - - Command_Toggle command = new Command_Toggle(); - command.defaultLabel = "CommandToggleTurret".Translate(); - command.defaultDesc = "CommandToggleTurretDesc".Translate(); - command.icon = ToggleTurretIcon.Texture; - command.isActive = () => - { - // 如果有混合状态,显示为false但使用特殊图标 - if (mixedState) - return false; - return allTurretsEnabled; - }; - command.toggleAction = () => - { - // 切换所有炮塔的状态 - bool newState = !allTurretsEnabled; - - foreach (var turretComp in allTurretComps) - { - turretComp.fireAtWill = newState; - - // 如果关闭炮塔,重置当前目标 - if (!newState) - { - turretComp.ResetCurrentTarget(); - } - } - }; - - // 如果有混合状态,显示特殊图标 - if (mixedState) - { - command.icon = ContentFinder.Get("UI/Commands/MixedState"); - } - - yield return command; + InitializeGizmo(); + gizmoInitialized = true; + } + + // 显示炮塔开关Gizmo + if (cachedGizmo != null) + { + yield return cachedGizmo; + } + + // 只有ID=0的主控炮塔显示集中火力Gizmo + if (IsMasterTurret && cachedFocusGizmo != null) + { + yield return cachedFocusGizmo; } } } + private void InitializeGizmo() + { + // 确定标签 + string label = !string.IsNullOrEmpty(Props.gizmoLabel) ? + Props.gizmoLabel : + Props.turretDef?.label ?? "Turrets".Translate(); + + // 确定标签 + string description = !string.IsNullOrEmpty(Props.gizmoDescription) ? + Props.gizmoDescription : + Props.turretDef?.description + "Wula_ToggleTurretgizmoDesc_Short".Translate(); + + // 确定图标 + Texture2D icon = ContentFinder.Get(Props.gizmoIconPath, false); + if (icon == null) + { + // 使用默认图标 + icon = ContentFinder.Get("UI/Gizmos/ToggleTurret", false) ?? BaseContent.BadTex; + } + + // 创建炮塔开关Gizmo + cachedGizmo = new Command_Toggle(); + cachedGizmo.defaultLabel = label + (Props.ID > 0 ? $" #{Props.ID}" : ""); + cachedGizmo.defaultDesc = description; + cachedGizmo.icon = icon; + cachedGizmo.isActive = () => FireAtWill; + cachedGizmo.toggleAction = () => + { + FireAtWill = !FireAtWill; + }; + + // 添加热键 + cachedGizmo.hotKey = KeyBindingDefOf.Misc1; + + // 为主控炮塔创建集中火力Gizmo + if (IsMasterTurret) + { + cachedFocusGizmo = new Command_Action(); + cachedFocusGizmo.defaultLabel = "Wula_FocusFire".Translate(); + cachedFocusGizmo.defaultDesc = "Wula_FocusFireDesc".Translate(); + cachedFocusGizmo.icon = ContentFinder.Get("UI/Gizmos/TargetFocus", false) ?? BaseContent.BadTex; + cachedFocusGizmo.action = () => + { + // 显示目标选择菜单 + ShowTargetSelectMenu(); + }; + + // 如果有集中火力目标,添加清除按钮 + if (focusTarget.IsValid && lastFocusPawn == parent) + { + cachedFocusGizmo.defaultLabel = "Wula_ClearFocus".Translate(); + cachedFocusGizmo.defaultDesc = "Wula_ClearFocusDesc".Translate(); + cachedFocusGizmo.icon = ContentFinder.Get("UI/Gizmos/TargetClear", false) ?? BaseContent.BadTex; + } + } + } + + private void ShowTargetSelectMenu() + { + // 如果已经有集中火力目标,清除它 + if (focusTarget.IsValid && lastFocusPawn == parent) + { + focusTarget = LocalTargetInfo.Invalid; + Messages.Message("Wula_FocusCleared".Translate(), MessageTypeDefOf.NeutralEvent); + return; + } + + // 创建目标选择器 + CameraJumper.TryJump(parent); + + // 显示选择目标的消息 + Messages.Message("Wula_SelectFocusTarget".Translate(), MessageTypeDefOf.NeutralEvent); + + // 设置目标选择回调 + TargetingParameters targetingParameters = new TargetingParameters(); + targetingParameters.canTargetPawns = true; + targetingParameters.canTargetBuildings = true; + targetingParameters.canTargetItems = false; + targetingParameters.canTargetLocations = false; + targetingParameters.canTargetSelf = false; + targetingParameters.canTargetFires = false; + targetingParameters.canTargetAnimals = true; + targetingParameters.canTargetHumans = true; + targetingParameters.canTargetMechs = true; + + // 添加地图上的所有有生命值的目标 + targetingParameters.validator = (TargetInfo targ) => + { + if (targ.Thing == null) + return false; + + // 必须有生命值 + if (targ.Thing.def.useHitPoints && targ.Thing.HitPoints > 0) + { + // 不能是友方(可选,根据需求调整) + if (targ.Thing.Faction != null && targ.Thing.Faction == parent.Faction) + { + // 如果是友方,需要特殊确认 + return false; + } + return true; + } + return false; + }; + + // 启动目标选择 + Find.Targeter.BeginTargeting(new TargetingParameters + { + canTargetLocations = true, + canTargetPawns = true, + canTargetBuildings = true, + canTargetItems = false + }, SetFocusTarget, null, OnFocusTargetCancelled); + } + + private void SetFocusTarget(LocalTargetInfo target) + { + if (target.Thing != null && target.Thing.Spawned) + { + focusTarget = target; + lastFocusSetTick = Find.TickManager.TicksGame; + lastFocusPawn = parent; + + Messages.Message( + "Wula_FocusTargetSet".Translate(target.Thing.LabelCap), + MessageTypeDefOf.PositiveEvent + ); + } + } + private void OnFocusTargetCancelled() + { + } + public override void PostExposeData() { base.PostExposeData(); @@ -588,15 +802,18 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref isAiming, "isAiming", false); Scribe_Values.Look(ref lastBaseRotationAngle, "lastBaseRotationAngle", 0f); Scribe_Values.Look(ref lastTargetAngle, "lastTargetAngle", 0f); + Scribe_Values.Look(ref resetCooldownTicksLeft, "resetCooldownTicksLeft", 0); + Scribe_Values.Look(ref isInResetCooldown, "isInResetCooldown", false); + + // 保存集中火力目标 + Scribe_TargetInfo.Look(ref focusTarget, "focusTarget"); + Scribe_Values.Look(ref lastFocusSetTick, "lastFocusSetTick", 0); + Scribe_References.Look(ref lastFocusPawn, "lastFocusPawn"); // 保存缺失的字段 Scribe_TargetInfo.Look(ref lastAttackedTarget, "lastAttackedTarget_" + Props.ID); Scribe_Values.Look(ref lastAttackTargetTick, "lastAttackTargetTick_" + Props.ID, 0); - // 保存复位冷却相关字段 - Scribe_Values.Look(ref resetCooldownTicksLeft, "resetCooldownTicksLeft", 0); - Scribe_Values.Look(ref isInResetCooldown, "isInResetCooldown", false); - if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (gun == null) @@ -616,6 +833,11 @@ namespace WulaFallenEmpire lastBaseRotationAngle = parent.Rotation.AsAngle; lastTargetAngle = currentRotationAngle; } + + // 重置 Gizmo 缓存 + gizmoInitialized = false; + cachedGizmo = null; + cachedFocusGizmo = null; } } diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 90c889b3..d8cd77ae 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -85,6 +85,7 @@ +