From 2ad42b6a7e6b8f3bdb97380a23b0601d8993b507 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 10 Dec 2017 16:58:48 +0000 Subject: [PATCH] Account for visibility when selecting AI superweapon targets. --- OpenRA.Mods.Common/AI/HackyAI.cs | 18 ++++--- OpenRA.Mods.Common/AI/SupportPowerDecision.cs | 54 ++++++++++++++++++- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/OpenRA.Mods.Common/AI/HackyAI.cs b/OpenRA.Mods.Common/AI/HackyAI.cs index 3498861f90..666e572e90 100644 --- a/OpenRA.Mods.Common/AI/HackyAI.cs +++ b/OpenRA.Mods.Common/AI/HackyAI.cs @@ -277,6 +277,7 @@ namespace OpenRA.Mods.Common.AI PowerManager playerPower; SupportPowerManager supportPowerMngr; PlayerResources playerResource; + FrozenActorLayer frozenLayer; int ticks; BitArray resourceTypeIndices; @@ -343,6 +344,7 @@ namespace OpenRA.Mods.Common.AI playerPower = p.PlayerActor.Trait(); supportPowerMngr = p.PlayerActor.Trait(); playerResource = p.PlayerActor.Trait(); + frozenLayer = p.PlayerActor.Trait(); foreach (var building in Info.BuildingQueues) builders.Add(new BaseBuilder(this, building, p, playerPower, playerResource)); @@ -1100,13 +1102,17 @@ namespace OpenRA.Mods.Common.AI { for (var j = 0; j < map.MapSize.Y; j += checkRadius) { - var consideredAttractiveness = 0; + var tl = new MPos(i, j); + var br = new MPos(i + checkRadius, j + checkRadius); + var region = new CellRegion(map.Grid.Type, tl, br); - var tl = World.Map.CenterOfCell(new MPos(i, j).ToCPos(map)); - var br = World.Map.CenterOfCell(new MPos(i + checkRadius, j + checkRadius).ToCPos(map)); - var targets = World.ActorMap.ActorsInBox(tl, br); + // HACK: The AI code should not be messing with raw coordinate transformations + var wtl = World.Map.CenterOfCell(tl.ToCPos(map)); + var wbr = World.Map.CenterOfCell(br.ToCPos(map)); + var targets = World.ActorMap.ActorsInBox(wtl, wbr); - consideredAttractiveness = powerDecision.GetAttractiveness(targets, Player); + var frozenTargets = frozenLayer.FrozenActorsInRegion(region); + var consideredAttractiveness = powerDecision.GetAttractiveness(targets, Player) + powerDecision.GetAttractiveness(frozenTargets, Player); if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) continue; @@ -1141,7 +1147,7 @@ namespace OpenRA.Mods.Common.AI var y = checkPos.Y + j; var pos = World.Map.CenterOfCell(new CPos(x, y)); var consideredAttractiveness = 0; - consideredAttractiveness += powerDecision.GetAttractiveness(pos, Player); + consideredAttractiveness += powerDecision.GetAttractiveness(pos, Player, frozenLayer); if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) continue; diff --git a/OpenRA.Mods.Common/AI/SupportPowerDecision.cs b/OpenRA.Mods.Common/AI/SupportPowerDecision.cs index a906379846..b8f6d0ad6f 100644 --- a/OpenRA.Mods.Common/AI/SupportPowerDecision.cs +++ b/OpenRA.Mods.Common/AI/SupportPowerDecision.cs @@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.AI } /// Evaluates the attractiveness of a position according to all considerations - public int GetAttractiveness(WPos pos, Player firedBy) + public int GetAttractiveness(WPos pos, Player firedBy, FrozenActorLayer frozenLayer) { var answer = 0; var world = firedBy.World; @@ -72,6 +72,16 @@ namespace OpenRA.Mods.Common.AI var checkActors = world.FindActorsInCircle(pos, radiusToUse); foreach (var scrutinized in checkActors) answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + + var delta = new WVec(radiusToUse, radiusToUse, WDist.Zero); + var tl = world.Map.CellContaining(pos - delta); + var br = world.Map.CellContaining(pos + delta); + var checkFrozen = frozenLayer.FrozenActorsInRegion(new CellRegion(world.Map.Grid.Type, tl, br)); + + // IsValid check filters out Frozen Actors that have not initizialized their Owner + foreach (var scrutinized in checkFrozen) + if (scrutinized.IsValid) + answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); } return answer; @@ -89,6 +99,18 @@ namespace OpenRA.Mods.Common.AI return answer; } + public int GetAttractiveness(IEnumerable frozenActors, Player firedBy) + { + var answer = 0; + + foreach (var consideration in Considerations) + foreach (var scrutinized in frozenActors) + if (scrutinized.IsValid && scrutinized.Visible) + answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + + return answer; + } + public int GetNextScanTime(HackyAI ai) { return ai.Random.Next(MinimumScanTimeInterval, MaximumScanTimeInterval); } /// Makes up part of a decision, describing how to evaluate a target. @@ -125,7 +147,7 @@ namespace OpenRA.Mods.Common.AI if (a == null) return 0; - if (!a.IsTargetableBy(firedBy.PlayerActor)) + if (!a.IsTargetableBy(firedBy.PlayerActor) || !a.CanBeViewedByPlayer(firedBy)) return 0; if (Types.Overlaps(a.GetEnabledTargetTypes())) @@ -147,6 +169,34 @@ namespace OpenRA.Mods.Common.AI return 0; } + + public int GetAttractiveness(FrozenActor fa, Stance stance, Player firedBy) + { + if (stance != Against) + return 0; + + if (fa == null || !fa.IsValid || !fa.Visible) + return 0; + + if (Types.Overlaps(fa.TargetTypes)) + { + switch (TargetMetric) + { + case DecisionMetric.Value: + var valueInfo = fa.Info.TraitInfoOrDefault(); + return (valueInfo != null) ? valueInfo.Cost * Attractiveness : 0; + + case DecisionMetric.Health: + var healthInfo = fa.Info.TraitInfoOrDefault(); + return (healthInfo != null) ? fa.HP * Attractiveness / healthInfo.HP : 0; + + default: + return Attractiveness; + } + } + + return 0; + } } } }