/// <summary> /// Gets the best block to target from a grid. /// </summary> /// <param name="grid">The grid to search</param> /// <param name="tType">Checked for destroy</param> /// <param name="target">The best block fromt the grid</param> /// <param name="distanceValue">The value assigned based on distance and position in blocksToTarget.</param> /// <remarks> /// <para>Decoy blocks will be given a distanceValue of the distance squared to weapon.</para> /// <para>Blocks from blocksToTarget will be given a distanceValue of the distance squared * (index + 1)^3.</para> /// <para>Other blocks will be given a distanceValue of the distance squared * (1e12).</para> /// </remarks> public bool GetTargetBlock(IMyCubeGrid grid, TargetType tType, out IMyCubeBlock target, out double distanceValue, bool doRangeTest = true) { Vector3D myPosition = ProjectilePosition(); CubeGridCache cache = CubeGridCache.GetFor(grid); target = null; distanceValue = double.MaxValue; if (cache == null) { return(false); } if (cache.TerminalBlocks == 0) { Log.TraceLog("no terminal blocks on grid: " + grid.DisplayName); return(false); } // get decoy block { foreach (IMyCubeBlock block in cache.BlocksOfType(typeof(MyObjectBuilder_Decoy))) { if (!TargetableBlock(block, true)) { continue; } double distanceSq = Vector3D.DistanceSquared(myPosition, block.GetPosition()); if (doRangeTest && distanceSq > Options.TargetingRangeSquared) { continue; } if (distanceSq < distanceValue && CanConsiderHostile(block)) { target = block; distanceValue = distanceSq; } } if (target != null) { Log.TraceLog("for type = " + tType + " and grid = " + grid.DisplayName + ", found a decoy block: " + target.DisplayNameText + ", distanceValue: " + distanceValue); return(true); } } // get block from blocksToTarget if (!Options.blocksToTarget.IsNullOrEmpty()) { int index = 0; IMyCubeBlock in_target = target; double in_distValue = distanceValue; foreach (MyDefinitionId[] ids in Options.listOfBlocks.IdGroups()) { index++; foreach (MyDefinitionId id in ids) { //Log.TraceLog("searching for blocks of type: " + id + ", count: " + cache.BlocksOfType(id).Count()); foreach (IMyCubeBlock block in cache.BlocksOfType(id)) { if (!TargetableBlock(block, true)) { continue; } double distSq = Vector3D.DistanceSquared(myPosition, block.GetPosition()); if (doRangeTest && distSq > Options.TargetingRangeSquared) { Log.TraceLog("out of range: " + block.nameWithId()); continue; } distSq *= index * index * index; if (distSq < in_distValue && CanConsiderHostile(block)) { in_target = block; in_distValue = distSq; } } } } target = in_target; distanceValue = in_distValue; if (target != null) // found a block from blocksToTarget { Log.TraceLog("for type = " + tType + " and grid = " + grid.DisplayName + ", target = " + target.DisplayNameText + ", distance = " + Vector3D.Distance(myPosition, target.GetPosition()) + ", distanceValue = " + distanceValue); return(true); } } // get any IMyTerminalBlock bool destroy = (tType & TargetType.Moving) != 0 || (tType & TargetType.Destroy) != 0; if (destroy || Options.blocksToTarget.IsNullOrEmpty()) { double closest = double.MaxValue; foreach (MyCubeBlock block in cache.AllCubeBlocks()) { if (block is IMyTerminalBlock && TargetableBlock(block, !destroy)) { double distanceSq = Vector3D.DistanceSquared(myPosition, block.PositionComp.GetPosition()); if (doRangeTest && distanceSq > Options.TargetingRangeSquared) { continue; } distanceSq *= 1e12; if (distanceSq < closest && CanConsiderHostile(block)) { target = block; distanceValue = distanceSq; } } } if (target != null) { Log.TraceLog("for type = " + tType + " and grid = " + grid.DisplayName + ", found a block: " + target.DisplayNameText + ", distanceValue = " + distanceValue); return(true); } } return(false); }