diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 0811d107..0b0ef4d8 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/Assemblies/WulaFallenEmpire.pdb b/1.6/1.6/Assemblies/WulaFallenEmpire.pdb index 1144fdc1..59c3f600 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.pdb and b/1.6/1.6/Assemblies/WulaFallenEmpire.pdb differ 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 cab90bf5..b3a867fc 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/WULA_Keyed.xml @@ -186,5 +186,6 @@ [P.I.A 轨道监视] 对敌方({0} 个目标)发射链炮扫射。 [P.I.A 轨道监视] 帝国舰队已抵达轨道。 [P.I.A 轨道监视] 航道已净空。 + [P.I.A 轨道监视] 对敌方建筑/炮台发射炮击。 diff --git a/Source/WulaFallenEmpire/EventSystem/AI/CompAbilityEffect_EnableOverwatch.cs b/Source/WulaFallenEmpire/EventSystem/AI/CompAbilityEffect_EnableOverwatch.cs index f4a09294..9d140f3f 100644 --- a/Source/WulaFallenEmpire/EventSystem/AI/CompAbilityEffect_EnableOverwatch.cs +++ b/Source/WulaFallenEmpire/EventSystem/AI/CompAbilityEffect_EnableOverwatch.cs @@ -8,6 +8,7 @@ namespace WulaFallenEmpire public class CompProperties_AbilityEnableOverwatch : CompProperties_AbilityEffect { public int durationSeconds = 180; // Default 3 minutes + public bool useArtilleryVersion = false; // Both use normal mothership by default public CompProperties_AbilityEnableOverwatch() { @@ -37,7 +38,7 @@ namespace WulaFallenEmpire map.components.Add(overwatch); } - overwatch.EnableOverwatch(Props.durationSeconds); + overwatch.EnableOverwatch(Props.durationSeconds, Props.useArtilleryVersion); } public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest) diff --git a/Source/WulaFallenEmpire/EventSystem/AI/MapComponent_AIOverwatch.cs b/Source/WulaFallenEmpire/EventSystem/AI/MapComponent_AIOverwatch.cs index 9e811e5e..07d929a2 100644 --- a/Source/WulaFallenEmpire/EventSystem/AI/MapComponent_AIOverwatch.cs +++ b/Source/WulaFallenEmpire/EventSystem/AI/MapComponent_AIOverwatch.cs @@ -26,7 +26,8 @@ namespace WulaFallenEmpire.EventSystem.AI { } - public void EnableOverwatch(int durationSeconds) + // useArtilleryVersion: false = WULA_MotherShip (normal), true = WULA_MotherShip_Planet_Interdiction (artillery) + public void EnableOverwatch(int durationSeconds, bool useArtilleryVersion = false) { if (this.enabled) { @@ -43,7 +44,7 @@ namespace WulaFallenEmpire.EventSystem.AI this.globalCooldownTicks = 0; // Call fleet when overwatch starts - TryCallFleet(); + TryCallFleet(useArtilleryVersion); Messages.Message("WULA_AIOverwatch_Engaged".Translate(clampedDuration), MessageTypeDefOf.PositiveEvent); } @@ -59,14 +60,16 @@ namespace WulaFallenEmpire.EventSystem.AI Messages.Message("WULA_AIOverwatch_Disengaged".Translate(), MessageTypeDefOf.NeutralEvent); } - private void TryCallFleet() + private void TryCallFleet(bool useArtilleryVersion) { try { - var flyOverDef = DefDatabase.GetNamedSilentFail("WULA_MotherShip_Planet_Interdiction"); + // Choose mothership version based on parameter + string defName = useArtilleryVersion ? "WULA_MotherShip_Planet_Interdiction" : "WULA_MotherShip"; + var flyOverDef = DefDatabase.GetNamedSilentFail(defName); if (flyOverDef == null) { - WulaLog.Debug("[AI Overwatch] Could not find WULA_MotherShip_Planet_Interdiction ThingDef."); + WulaLog.Debug($"[AI Overwatch] Could not find {defName} ThingDef."); return; } @@ -80,14 +83,14 @@ namespace WulaFallenEmpire.EventSystem.AI startPos, endPos, map, - speed: 0.02f, // Slower for mothership + speed: useArtilleryVersion ? 0.02f : 0.01f, // Artillery version slower height: 20f ); if (flyOver != null) { Messages.Message("WULA_AIOverwatch_FleetCalled".Translate(), MessageTypeDefOf.PositiveEvent); - WulaLog.Debug($"[AI Overwatch] Called fleet: WULA_MotherShip_Planet_Interdiction spawned from {startPos} to {endPos}."); + WulaLog.Debug($"[AI Overwatch] Called fleet: {defName} spawned from {startPos} to {endPos}."); } } catch (Exception ex) @@ -206,26 +209,65 @@ namespace WulaFallenEmpire.EventSystem.AI private void PerformScanAndStrike() { - // Gather all valid hostile targets - List hostiles = map.mapPawns.AllPawnsSpawned + // Gather all valid hostile pawn targets + List hostilePawns = map.mapPawns.AllPawnsSpawned .Where(p => !p.Dead && !p.Downed && p.HostileTo(Faction.OfPlayer) && !p.IsPrisoner) .ToList(); - if (hostiles.Count == 0) return; + // Gather all hostile buildings (turrets, etc.) + List hostileBuildings = map.listerBuildings.allBuildingsColonist + .Concat(map.listerThings.ThingsInGroup(ThingRequestGroup.BuildingArtificial).OfType()) + .Where(b => b != null && !b.Destroyed && b.Faction != null && b.Faction.HostileTo(Faction.OfPlayer)) + .Distinct() + .ToList(); - // Simple clustering: Group hostiles that are close to each other - var clusters = ClusterPawns(hostiles, 12f); // 12 tile radius for a cluster + // Convert building positions to "virtual targets" for processing + List buildingTargets = hostileBuildings.Select(b => b.Position).ToList(); - // Prioritize larger clusters - clusters.Sort((a, b) => b.Count.CompareTo(a.Count)); // Descending order - - // Process clusters _strikesThisScan = 0; - foreach (var cluster in clusters) + // Process hostile pawns first (clustered) + if (hostilePawns.Count > 0) { - if (globalCooldownTicks > 0) break; - ProcessCluster(cluster); + var clusters = ClusterPawns(hostilePawns, 12f); + clusters.Sort((a, b) => b.Count.CompareTo(a.Count)); + + foreach (var cluster in clusters) + { + if (globalCooldownTicks > 0) break; + if (_strikesThisScan >= 3) break; + ProcessCluster(cluster); + } + } + + // Process hostile buildings (each as individual target) + foreach (var buildingPos in buildingTargets) + { + if (globalCooldownTicks > 0) break; + if (_strikesThisScan >= 3) break; + ProcessBuildingTarget(buildingPos); + } + } + + private void ProcessBuildingTarget(IntVec3 target) + { + if (!target.InBounds(map)) return; + + float safetyRadius = 9.9f; // Medium safety for building strikes + if (IsFriendlyFireRisk(target, safetyRadius)) + { + Messages.Message("WULA_AIOverwatch_FriendlyFireAbort".Translate(target.ToString()), new TargetInfo(target, map), MessageTypeDefOf.CautionInput); + return; + } + + // Use cannon salvo for buildings (good balance of damage and precision) + var cannonDef = DefDatabase.GetNamedSilentFail("WULA_Firepower_Cannon_Salvo"); + if (cannonDef != null) + { + Messages.Message("WULA_AIOverwatch_EngagingBuilding".Translate(), new TargetInfo(target, map), MessageTypeDefOf.PositiveEvent); + WulaLog.Debug($"[AI Overwatch] Engaging hostile building at {target} with Cannon Salvo."); + FireAbility(cannonDef, target, Rand.Range(0, 360)); + _strikesThisScan++; } }